动态SQL简介:
1、静态SQL
静态SQL是指直接嵌入在PL/SQL块中的SQL语句。在编写PL/SQL时。静态SQL用于完成特定或固定的任务:
2、动态SQL
动态SQL是指在运行PL/SQL块时动态输入的SQL语句。如果在PL/SQL中需要执行DDL语句,DCL语句(GRANT,REVOKE),或者在PL/SQL中需要执行更加灵活的SQL语句(例如在SELECT语句中使用不同的WHERE条件),那么就必须使用动态SQL。
在PL/SQL块中编写动态语句时,需要将SQL语句存放在字符创变量中,而且SQL语句可以包含占位符(以冒号开始)。
如:CREATE TABLE temp(cola INT,colb VARCHAR2(10))
GRANT SELECT ON temp TO smith
DELETE FROM emp WHERE sal>:a
SELECT ename,sal FROM emp WHERE empno=:l
3、动态SQL的处理方法
(1)、使用EXECUTE IMMEDIATE
不能用于处理多行查询语句。
(2)、使用OPEN-FOR FETCH 和CLOSE语句
为了处理动态的多行查询操作,必须使用OPEN-FOR语句打开游标,使用FETCH 语句提取循环数据,最终使用CLOSE语句关闭游标.
(3)、使用批量动态SQL
处理非查询语句
为了动态的处理非查询语句(DML DDL DCL)或者单行查询语句,可以在PL/SQL快中使用EXEXUTE IMMEDIATE 语句,
EXECUTE IMMEDIATE dynamic_string
[INTO |define_variable|,define_variable...|record]
[USING [IN|OUT|INOUT] bind_argument...]
[{RETURNING|RETURN} INTO bind_argument...];
dynamic_string 用于指定存放SQL语句或者PL/SQL块的字符串变量;
define_variable用于指定存放单行查询结婚的变量
输入bind_argument(IN)用于指定存放被传递给动态SQL值的变量
输出bind_argument(OUT)用于指定存放动态SQL返回值的变量
1、使用EXECUTE IMMEDIATE 处理DDL操作
EXECUTE IMMEDIATE后面只需要带有DDL语句文本即可,而不需要INTO和USING
字句。
CREATE OR REPLACE PROCEDURE drop_table(table_name VARCHAR2)
IS
sql_statement VARCHAR2(100);
BEGIN
sql_statement:='DROP TABLE '||table_name;
EXECUTE IMMEDIATE sql_statement;
END;
2、使用EXECUTE IMMEDIATE 处理DCL操作
和处理DDL语句差不多
3、使用EXECUTE IMMEDIATE 处理DML 语句
如果DML语句既没有占位符,也咩有RETURNING 字句,那么在EXECUTE IMMEDIATE 语句之后不需要带有USING和RETURNING INTO子句;
如果DML语句含有占位符,那么在 EXECUTE IMMEDIATE 语句之后要带有USING子句;
如果DML语句之后带有RETURNING子句,那么在EXECUTE IMMEDIATE 语句之后带有RETURNING INTO子句。
(1)、处理无占位符和RETURNING子句的DML语句
DECLARE
sql_statement VARCHAR2(100);
BEGIN
sql_statement:='UPDATE emp SET sal=sal*1.1 WHERE depno=30';
EXECUTE IMMEDIATE sql_statement;
END;
(2)、处理包含占位符的DML语句
要使用USING 自己为占位符提供输入数据。
DECLARE
sql_state VARCHAR2(100);
BEGIN
sql_state:='UPDATE emp SET sal=sal*(1+:percent/100) WHRE deptno=:dno';
EXECUTE IMMEDIATE sql_state USING &1,&2;
END;
(3)、处理包含RETURNING 子句的DML语句
必要要使用RETURNING INTO 子句接受返回数据。
注意:直接使用EXECUTE IMMEDIATE 语句处理带有RETURNING 子句的DML语句时,只能处理作用在单行的DML语句。
如果DML语句作用在多行伤,则必须要使用BULK子句。
DECLARE
salary NUMBER(6,2);
sql_state VARCHAR2(100);
BEGIN
sql_state:='UPDATE emp SET sal=(sal*:present/100) WHERE empno=:eno RETURNING sal INTO :salary';
EXECUTE IMMEDIATE sql_state USING &1,&2 RETURNING INTO salary;
dbms_output.put_line('新工资:'||salary);
END;
(4)、使用EXECUTE IMMEDIATE 处理单行查询
要使用INTO 子句接受返回数据
DECLARE
sql_state VARCHAR2(100);
emp_record emp%ROWTYPE;
BEGIN
sql_state:='SELECT * FROM emp WHERE empno=:eno';
EXECUTE IMMEDIATE sql_state INTO emp_record USING &1;
dbms_output.put_line('雇员:'||emp_record.ename||'的工资为:'||emp_record.sal);
END;
处理多行查询语句:
使用EXECUTE IMMEDIATE只能处理单行查询语句,为了动态的处理SELECT语句所返回的多行数据,需要使用OPEN-FOR,FETCH,CLOSE语句。
步骤如下
定义游标变量-->打开游标变量-->循环提取数据-->关闭游标变量。
1、定义游标变量:
TYPE cursortype IS REF CURSOR;
cursor_variable cursortype;
2、打来游标变量
OPEN cursor_variable FOR dynamic_string [USING bind_argument,...];
bind_argument 用于存放传递给动态SELECT语句值的变量。
3、循环提取数据
FETCH cursor_variable INTO {var1[,var2]...|record_var};
4、关闭游标变量
close cursor_variable;
5、多行查询实例:
DECLARE
TYPE cursor_type IS REF CURSOR;
sql_state VARCHAR2(100);
emp_record emp%ROWTYPE;
v_cursor vursor_type;
BEGIN
sql_state:='SELECT * FROM emp WHERE deptno=:dno';
OPEN v_cursor FOR sql_state USING &deptno;
LOOP
FETCH v_cursor INTO emp_record;
EXIT WHEN v_cursor%NOTFOUND;
dbms_output.put_line('雇员名:'||emp_record.ename||'的工资是:'||emp_record.salary);
END LOOP;
CLOSE v_cursor;
END;
在动态SQL中使用BULK子句
ORACLE9i新增加的特性。可以加快批量数据的处理速度。
有三种语句支持BULK子句:EXECUTE IMMEDIATE,FETCH和FORALL
1、在EXECUTE IMMEDIATE语句中使用动态BULK子句
EXECUTE IMMEDIATE dynamic_string
[BULK COLLECT INTO |define_variable|,define_variable...|record]
[USING [IN|OUT|INOUT] bind_argument...]
[{RETURNING|RETURN} BULK COLLECT INTO bind_argument...];
(1)、使用BULK子句处理DML语句返回子句
DECLARE
TYPE ename_table_type IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
TYPE sal_table_type IS TABLE OF emp.sal%TYPE INDEX BY BINARY_INTEGER;
ename_table ename_table_type;
sal_table sal_table_type;
sql_state VARCHAR2(150);
BEGIN
sql_state:='UPDATE emp SET sal=sal*(1+:precent/100) WHERE deptno=:dno'
||'RETURNING ename,sal INTO :name,:salary';
EXECUTE IMMEDIATE sql_state USING &precent,&depno RETURNING BULK COLLECT INTO
ename_table,sal_table ;
FOR i IN 1..ename_table.COUNT LOOP
dbms_output.put_line('雇员名:'||ename_table(i)||'的工资是:'||sal_table(i));
END LOOP;
END;
(2)、使用BULK子句处理多行查询
DECLARE
sql_state VARCHAR2(100);
TYPE ename_table_type IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
ename_table ename_table_type;
BEGIN
sql_state:='SELECT ename FROM emp WHERE empno=:eno';
EXECUTE IMMEDIATE sql_state BULK COLLECT INTO emp_record USING &1;
FOR i IN 1..ename_table.COUNT LOOP
dbms_output.put_line('雇员:'||ename_table(i));
END LOOP;
END;
2、在FETCH 语句中使用BULK子句
OPEN-FOR ,FETCH,CLOSE .....BULK
DECLARE
TYPE cursor_type IS REF CURSOR;
TYPE ename_table_type IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
sql_state VARCHAR2(200);
v_vursor cursor_type;
ename_table ename_table_type;
BEGIN
sql_state:='SELECT ename FROM emp WHERE deptno=:dno';
OPEN v_corsor FOR sql_state USING &deptno;
FETCH v_cursor BULK COLLECT INTO ename_table;
FOR i IN i..ename_table.COUNT LOOP
dbms_output.put_line('雇员:'||ename_table(i));
END LOOP;
CLOSE v_cursor;
END;
FORALL