Oracle系列之五——动态SQL

Oracle系列之五——动态SQL

一.简介

SQL语句包含静态SQL和动态SQL两种。静态SQL一般用来完成一些相对固定的任务,这种SQL在执行时已经编译完成。但是,一些PL/SQL程序要求必须在运行时建立和处理SQL语句,这种SQL语句只有在执行时才能确定,所以被称为动态SQL.

相对来说,静态SQL语句的性能要优于动态SQL语句;因而在编写PL/SQL块时,如果功能完成确定,则应该使用静态SQL;如果不能确定要执行的SQL语句,则使用动态SQL.

在PL/SQL块中编写动态SQL语句时,需要将SQL语句存放到字符串变量中,而且SQL语句可以包含占位符(以冒号开始);

二.SQL的处理方法

根据动态SQL语句的不同,可以使用三种不同类型的动态SQL方法。

  1. 使用EXECUTE IMMEDIATE语句

    Execute immediate语句可以处理大多数动态SQL操作,包括DDL语句(CREATE,ALTER,DROP)、DCL语句(grant,revoke)、DCL语句(INSERT,UPDATE,DELETE),以及单行SELECT语句.注意,execute immediate语句不能用于处理多行查询语句.

    语法如下:

    Execute immediate dynamin_string

    [into {defined_variable[,define_variable]…|record}]

    [using [in | out | in out] bind_argument [,in | out | in out ] bind_argument]….]

    [{returning | return } into bind_argument [,bind_argument]…];

    示例1,处理DDL操作:

create or replace procedure drop_table(table_name varchar2) is

sql_statement varchar2(100);

begin

sql_statement :=\'drop table \'|| table_name;

end;

示例2,处理DCL操作

create or replace procedure grant_sys_priv(priv varchar2,

username varchar2) is

sql_state varchar2(100);

begin

sql_state :=\'grant \'|| priv ||\' to \'|| username;

execute immediate sql_state;

end;

示例3,处理DML操作

在使用execute immediate语句处理DML语句时,如果DML语句即没有占位符,也没有returning语句,那么在execute immediate 语句之后不需要带有using和returing into 子句.如果DML操作包含占位符,则必须包含using 子句;如果DML语句带有returning语句,那么在EXECUTE IMMEDIATE语句之后需要带有returning into 子句.

--无占位符和returning子句

declare

sql_stat varchar2(100);

begin

sql_stat :=\'update emp set sal=sal*1.1\';

execute immediate sql_stat;

end;

--有占位符和无returning子句

declare

sql_stat varchar2(100);

begin

sql_stat :=\'update emp set sal=sal*(1+:percent/100)\';

execute immediate sql_stat using &1;

end;

--有占位符和returning子句

declare

sql_stat varchar2(100);

salary number(6,2);

begin

--dml语句中有returning子句

sql_stat :=\'update emp set sal=sal*(1+:percent/100) where empno=:no returning sal into :salary\';

execute immediate sql_stat

using &1,&2

--对应的,这必须有returning into 语句

returning into salary;

dbms_output.put_line(\'新工资:\'|| salary);

end;

--单行select语句

declare

sql_stat varchar2(100);

emp_record emp%rowtype;

begin

--占位符

sql_stat :=\'select * from emp where empno=:no\';

execute immediate sql_stat

into emp_record

--对应的,要用using子句

using &1;

dbms_output.put_line(\'姓名:\'|| emp_record.ename ||\' 工资:\'||

emp_record.sal);

end;

  1. 使用OPEN-FOR,FETCH和CLOSE语句

    为了处理动态的多行查询操作,必须要使用OPEN-FOR语句打开游标,使用FETCH语句循环提取数据,最终使用CLOSE语句关闭游标.

declare

type emp_cursor_type is ref cursor;

emp_cursor emp_cursor_type;

emp_record emp%rowtype;

sql_stat varchar2(100);

begin

sql_stat :=\'select * from emp where deptno=:no\';

open emp_cursor for sql_stat

using &no;

loop

fetch emp_cursor

into emp_record;

exit when emp_cursor%notfound;

dbms_output.put_line(\'name:\'|| emp_record.ename ||\' ,sal:\'||

emp_record.sal);

end loop;

end;

  1. 使用批量动态SQL

    批量动态SQL是ORACLE 9i新增加的特性.通过使用批量动态SQL,可以加快sql语句处理,进而提高PL/SQL程序的性能.

通过使用BULK子句,可以加快批量数据的处理速度,从而提高应用程序的性能.当使用Bulk子句时,实际上是动态SQL语句将变量绑定为集合元素.语法如下:

Execute immediate dynamin_string

[bulk collect into {defined_variable[,define_variable]…|record}]

[using [in | out | in out] bind_argument [,in | out | in out ] bind_argument]….]

[{returning | return } bulk collect into bind_argument [,bind_argument]…];

示例如下:

处理单行语句:

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_Stat varchar2(100);

--name emp.ename%type;

--salary emp.sal%type;

begin

sql_stat :=\'update emp set sal=sal*(1+:percent/100) where empno=:no returning ename,sal into :na,:sala\';

execute immediate sql_Stat

using &1, &2

returning bulk collect

into ename_table, sal_table;

for i in1 .. ename_table.count loop

dbms_output.put_line(\'姓名:\'|| ename_table(i)||\' 薪水:\'|| sal_table(i));

end loop;

end;

处理多行语句:

declare

type ename_table_type is table of emp.ename%type index by binary_integer;

ename_table ename_table_type;

sql_Stat varchar2(100);

begin

sql_stat :=\'select ename from emp\';

execute immediate sql_Stat

-- using &1, &2

bulk collect

into ename_table;--, sal_table;

for i in1 .. ename_table.count loop dbms_output.put_line(\'姓名:\'|| ename_table(i));--|| \'薪水:\' || sal_table(i)--);

end loop;

end;