动态SQL
(1).区分静态SQL和动态SQL
(2).用动态SQL处理非查询语句
(3).使用动态SQL处理多行查询语句
(4).用集合处理动态SQL语句
1.静态SQL
静态SQL指直接嵌入在PL/SQL块中的SQL语句,静态SQL用于完成特定或固定的任务。
select sal from emp where empno=4000;
2.动态SQL
动态SQL运行PL/SQL块时动态输入的SQL语句。若是在PL/SQL须要执行DDL语句,DCL语句,或则须要执行更加灵活的SQL语句(select中有不一样where条件),须要用到用到动态SQL。
编写动态SQL语句时,须要将SQL语句存放到字符串变量中,并且SQL语句能够包含占位符(以冒号开始)。
v_sql varchar2(100);
v_sql:='delete from emp where empno =:v_empno';
3.三种不一样类型的动态SQL方法
(1)使用execute immediate 语句
除不能处理多行查询语句,其余的动态SQL包括DDL语句,DCL语句以及单行的SELECT查询均可以。
(2)ref cursor 动态游标,使用open-for,fetch,close
能处理动态的多行查询操做,必需要使用open-for语句打开游标,使用fetch语句循环提取数据,最终使用close语句关闭游标。
(3)使用批量bulk collect动态SQL
经过使用批量动态SQL语句,能够加快SQL语句处理,进而提升PL/SQL的性能。
4.execute immediate语句语法
execute immediate dynamic_string
[into {define_variable[,define_variable...]}]
[using [in|out|in out] bind_argument]
[{return|returning} into bind_argument...]
#######execute immeidate
(1)使用execute immeidate语句处理单行DDL操做
//删除某个表
create or replace procedure pro_drop_table(v_table_name varchar2)
is
v_sql varchar2(100);
begin
v_sql := 'drop table ' || v_table_name;
execute immediate v_sql;
end;
(2)处理DCL操做
//授予某个权限给某个用户
create or replace procedure pro_grant_priv(v_priv varchar2,v_username varchar2)
is
v_sql varchar2(100);
begin
v_sql := 'grant ' || v_priv || ' to ' || v_username;
execute immediate v_sql;
end;
//测试
exec pro_grant_priv('create session','test_1')
(3)处理DML操做
若是DML语句中包含占位符,那么在execute immediat语句以后必需要带有using语句。若是DML语句中带有returning子句,那么在execute immediate语句以后须要带有returning into子句
//给不一样部门增长工资
declare
v_sql varchar2(100);
begin
v_sql := 'update emp set sal = sal*(1+:v_percent/100) where deptno=:v_deptno';
execute immediate v_sql using &1,&2;
end;
################ref cursor 动态游标的使用
5.使用open..for,fetch..into,close语句
动态处理select语句返回多行数据
(1)定义游标变量
type cursor_type is ref cursor;
cursor_variable cursor_type;
(2)打开游标变量
open cursor_variable for dynamic_string
[using bind_argument....];
(3)循环提取数据
fetch cursor_variable into {var1,var2....|record_var};
var指提取表量变量,record_var提取记录变量。
(4)关闭游标
close cursor_variable;
//显示指定部门的全部雇员名和工资
create or replace procedure pro_info(v_deptno number)
is
type emp_cursor_type is ref cursor;
emp_cursor emp_cursor_type;
emp_record emp%rowtype;
v_sql varchar2(100);
begin
v_sql:='select * from emp where deptno=:v_deptno';
open emp_cursor for v_sql using v_deptno;
loop
fetch emp_cursor into emp_record;
exit when emp_cursor%notfound;
dbms_output.put_line('ename: '|| emp_record.ename ||',salary: ' ||emp_record.sal);
end loop;
close emp_cursor;
end;
##########bulk collect的使用
6.批量动态SQL---bulk
bulk加快批量数据的处理速度,使用bulk子句时,实际是动态SQL语句将变量绑定为集合元素。
集合元素必须使用SQL数据类型(char,number,varchar2,date,timestamp),不能使用PL/SQL数据类型(binary_integer,boolean)。
动态BULK子句的语法:
execute immediate dynamic_string
[bulk collect into define_variable...]
[using bind_argument...]
[{returning | return} bulk collect into return_variable...]
//显示特定部门的全部雇员名
set serveroutput on;
declare
type ename_table_type is table of emp.ename%type index by binary_integer;
ename_table ename_table_type;
v_sql varchar2(100);
begin
v_sql:='select ename from emp where deptno=:v_deptno';
execute immediate v_sql bulk collect into ename_table using &v_deptno;
for i in 1..ename_table.count loop
dbms_output.put_line(ename_table(i));
end loop;
end;
做业:
1.动态修改特定部门的工资,并返回修改后的雇员名和工资---scott---emp
//使用游标
create or replace procedure pro_change_sal(v_deptno emp.deptno%type,v_percent number)
is
type cursor_emp_type is ref cursor;
emp_record emp%rowtype;
emp_cursor cursor_emp_type;
v_sql varchar2(100);
begin
update emp set sal=sal*(1+v_percent/100) where deptno=v_deptno;
v_sql:='select * from emp where deptno=v_deptno';
open emp_cursor for v_sql ;
loop
fetch emp_cursor into emp_record;
exit when emp_cursor%notfound ;
dbms_output.put_line('ename: '|| emp_record.ename ||',salary: ' ||emp_record.sal);
end loop;
close emp_cursor;
end;
####################
//批量处理
set serveroutput on;
create or replace procedure pro_change_sal(v_deptno emp.deptno%type,v_percent number)
is
type sal_table_type is table of emp.sal%type index by binary_integer;
type ename_table_type is table of emp.ename%type index by binary_integer;
ename_table ename_table_type;
sal_table sal_table_type;
v_sql varchar2(100);
begin
update emp set sal=sal*(1+v_percent/100) where deptno=v_deptno;
v_sql:='select ename,sal from emp where deptno=:v_deptno';####必须使用:v_deptno加冒号
execute immediate v_sql bulk collect into ename_table,sal_table using v_deptno;
for i in 1..ename_table.count loop
dbms_output.put_line('ename: '|| ename_table(i) ||',salary: ' ||sal_table(i));
end loop;
end;
2.根据输入的多个订单号更新交付日期为当前日期,并返回每隔订单的对应的客户编号.
create or replace procedure pro_change_ship_date(id1 number,id2 number,id3 number)
is
type customer_id_table_type is table of number;
type ordre_id_table_type is table of number;
customer_id_table customer_id_table_type;
ordre_id_table ordre_id_table_type;
v_sql varchar2(100);
begin
update orders set ship_date=sysdate where order_id in (id1 ,id2 ,id3);
v_sql :='select customer_id, order_id from orders where order_id in ( :id1 ,:id2 ,:id3)';
execute immediate v_sql bulk collect into customer_id_table,ordre_id_table using id1 ,id2 ,id3;
for i in 1.. customer_id_table.count loop
dbms_output.put_line('ordre_id '||ordre_id_table(i)||' '||'customer_id '||customer_id_table(i));
end loop;
end;
sql