Oracle 动态SQL语句

Oracle 动态SQL语句


   
EXECUTE IMMEDIATE代替了以前Oracle8i中DBMS_SQLpackage包. 
它解析并马上执行动态的SQL语句或非运行时创建的PL/SQL块.动态创建和执行SQL语句性能超前,EXECUTEIMMEDIATE的目标在于减小企业费用并获得较高的性能,较之以前它相当容易编码.尽管DBMS_SQL仍然可用,但是推荐使用EXECUTEIMMEDIATE,因为它获的收益在包之上。

-- 使用技巧 

1. EXECUTE IMMEDIATE将不会提交一个DML事务执行,应该显式提交 
如果通过EXECUTE IMMEDIATE处理DML命令, 
那么在完成以前需要显式提交或者作为EXECUTE IMMEDIATE自己的一部分. 
如果通过EXECUTE IMMEDIATE处理DDL命令,它提交所有以前改变的数据 

2. 不支持返回多行的查询,这种交互将用临时表来存储记录(参照例子如下)或者用REFcursors. 

3. 当执行SQL语句时,不要用分号,当执行PL/SQL块时,在其尾部用分号. 

4. 在Oracle手册中,未详细覆盖这些功能。 
下面的例子展示了所有用到Executeimmediate的可能方面.希望能给你带来方便. 

5. 对于Forms开发者,当在PL/SQL 8.0.6.3.版本中,Forms6i不能使用此功能. 

EXECUTE IMMEDIATE --用法例子 

1. 在PL/SQL运行DDL语句 

begin 
   execute immediate 'set roleall'; 
end; 

2. 给动态语句传值(USING子句) 

declare 
   l_depnam varchar2(20) :='testing'; 
  l_loc    varchar2(10) := 'Dubai'; 
   begin 
   execute immediate 'insert intodept values   (:1, :2,:3)' 
    using 50, l_depnam,l_loc; 
  commit;   -----一定要显示提交
end; 

3. 从动态语句检索值(INTO子句) 

declare 
  l_cnt    varchar2(20); 
begin 
   execute immediate 'selectcount(1) from emp' 
    into l_cnt; 
  dbms_output.put_line(l_cnt); 
end; 

4. 动态调用例程.例程中用到的绑定变量参数必须指定参数类型. 
黓认为IN类型,其它类型必须显式指定 

declare 
  l_routin   varchar2(100) := 'gen2161.get_rowcnt'; 
  l_tblnam   varchar2(20) := 'emp'; 
  l_cnt      number; 
  l_status   varchar2(200); 
begin 
   execute immediate 'begin ' ||l_routin || '(:2, :3, :4);end;' 
    using in l_tblnam, out l_cnt, in outl_status; 
   if l_status != 'OK'then 
     dbms_output.put_line('error'); 
   endif; 
end; 

5. 将返回值传递到PL/SQL记录类型;同样也可用%rowtype变量 

declare 
   type empdtlrec is record(empno  number(4), 
                           ename  varchar2(20), 
                           deptno  number(2)); 
   empdtlempdtlrec; 
begin 
   execute immediate 'selectempno, ename, deptno ' || 
                   'from emp where empno = 7934' 
    into empdtl; 
end; 

6. 传递并检索值.INTO子句用在USING子句前 

declare 
  l_dept    pls_integer := 20; 
  l_nam     varchar2(20); 
  l_loc     varchar2(20); 
begin 
   execute immediate 'selectdname, loc from dept where deptno = :1' 
    into l_nam, l_loc 
    using l_dept ; 
end; 

7. 多行查询选项.对此选项用insert语句填充临时表, 
用临时表进行进一步的处理,也可以用REF cursors纠正此缺憾. 
declare 
  l_sal   pls_integer := 2000; 
begin 
   execute immediate 'insert intotemp(empno, ename) ' || 
                   '          select empno, ename from emp ' || 
                   '          where   sal >:1' 
    using l_sal; 
  commit; 
end; 

       对于处理动态语句,EXECUTE IMMEDIATE比以前可能用到的更容易并且更高效. 
当意图执行动态语句时,适当地处理异常更加重要.应该关注于捕获所有可能的异常.

Oracle的动态SQL和动态游标举例:
--动态sql和动态游标 

declare 
  cnt number;  
begin 
  execute immediate 
  'select count(*) fromemp' 
  into cnt; 
  dbms_output.put_line(cnt); 
end; 
 
--创建存储过程执行插入语句 
create or replace procedure myproc11 
(empid in varchar2,empname in varchar2) 
is 
  sql_str varchar(200):='insert into empvalues(:a,:b)';      
begin 
  execute immediatesql_str usingempid,empname
  commit; 
end; 
 
--本过程有两个参数, 第一个表示查询类型 :0-精确查询1-模糊查询; 
-- 第二个参数表示查询条件  
create or replace procedure myproc12 
(query_type in number,empname in varchar2) 
is 
  sql_str varchar(200):='select * from emp'; 
  cur pck1.myrefcur; 
  e emp%rowtype;    
begin 
   
  if query_type=0 then 
    sql_str:=sql_str||'whereemp_name=:1'; 
  else 
      sql_str:=sql_str||'where emp_name like''%''||:1||''%'''; 
  end if; 
  dbms_output.put_line(sql_str); 
  open cur for sql_str usingempname; 
 
  loop 
    fetch cur intoe; 
    exit whencur%notfound; 
    dbms_output.put_line(e.emp_id||','||e.emp_name); 
  end loop; 
  close cur; 
end; 
 
--按姓名模糊查询记录总数 
create or replace procedure myproc20 
(ename in varchar2) 
is 
  cnt number;  
begin 
  execute immediate 
  'select count(*) from emp where emp_name like''%''||:n||''%''' 
  into cnt using ename; 
  dbms_output.put_line(cnt); 
end; 


使用executeimmediate语句可以处理包括ddl(create、alter和drop)、DCL(grant、revoke)、DML(insert、update、delete)以及单行select语句。

execute immediate语句:
       executeimmediate dynamic_string
       [into{define_variable[,define_variable]…|record}]
       [using[in|out|in out] bind_argument[,[in|out|in out]bind_argument]…]
       [{returning|return}into bind_argument[, bind_argument]…]

Define_variable用于指定存放单行查询结果的变量;

using in bind_argument用于指定存放传递给动态sql值的变量,即在dynamic中存在占位符时使用;

using out bind_argument用于指定存放动态sql返回值的变量。

示例:使用execute immediate执行简单ddl语句
    begin

execute immediate 'create tablema_org(org_code varchar2(20),org_name varchar2(254))';
        executeimmediate 'drop table ma_org';
    end;

实例:使用execute immediate执行dcl语句
    begin
        executeimmediate 'grant insert on ma_org to scott'
    end;

示例:使用execute immediate处理dml语句。

如果dml语句包含占位符,那么在executeimmediate语句之后必须要带有using子句;如果dml语句带有returning子句,那么在execute immediate语句之后必须带有returning into子句并且此时只能处理作用的单行上的dml语句,如果dml语句作用在多行上,则必须使用bulk子句

示例:

declare
          orgcodevarchar2(10);
          orgnamevarchar2(254);
    begin
          orgcode:= 1200;
          executeimmediate 'select org_name fromma_org 
          whereorg_code = :X'
          intoorgname
          usingorgcode; 
          dbms_output.put_line(orgname);
    end;

示例:

declare
          orgcodevarchar2(10);
          orgnamevarchar2(254);
          rnamevarchar2(254);
    begin
          orgcode:= '1200';
          orgname:= '天津市分行';
          executeimmediate 'update ma_org set org_name=:X 
          whereorg_code = :Y returning org_name into :rname'
          usingorgname, orgcode
          returninginto rname; 
          dbms_output.put_line(orgname);
    end;

使用动态游标处理多行查询类动态sql语句。

示例:

declare
          typemyrefcursor is ref cursor;
          refcursormyrefcursor;
          rec_ma_orgma_org%rowtype;
    begin
          openrefcursor for select * from ma_org;
               loop
                   fetchrefcursor into rec_ma_org;
                   exitwhenrefcursor%notfound;    
                   dbms_output.put_line(rec_ma_org.org_code||','||rec_ma_org.org_name);
               endloop;
          closerefcursor;
    end;

oracle通过使用bulk collectinto子句处理动态sql中的多行查询可以加快处理速度,从而提高应用程序的性能。当使用bulk子句时,集合类型可以是plsql所支持的索引表、嵌套表和varray,但集合元素必须使用sql数据类型。在oracle9i以后,有三种语句支持bulk子句,executeimmediate,fetch和forall。

在execute immediate中使用bulk collect into处理多行查询返回结果:

示例:

declare
          typeorg_table_type is table of ma_org%rowtype;
          org_tableorg_table_type;
          v_orgcodevarchar2(20);
    begin
          v_orgcode:= '%';
          executeimmediate 'select * from ma_org where org_code like :v_orgcode'bulk collect into org_table
          usingv_orgcode;
          fori in 1..org_table.count
              loop    
                 dbms_output.put_line(org_table(i).org_code||','||org_table(i).org_name);
              endloop; 
    end;

在forall语句中使用bulkinto语句。

示例:

declare
          typetype_org_code is table of ma_org.org_code%type;
          typetype_org_name is table of ma_org.org_name%type;
          v_orgcodetype_org_code;
          v_orgnametype_org_name;
    begin
          v_orgcode:= type_org_code('1100','1200'); 
          foralli in 1..v_orgcode.count
             executeimmediate 'update ma_org set org_name = org_code||org_name whereorg_code = :p1 returning org_name into :p2'
             usingv_orgcode(i)
             returningbulk collect into v_orgname; 
          fori in v_orgname.first..v_orgname.last
             loop
                dbms_output.put_line(v_orgname(i));
          endloop;
    end;


一般的PL/SQL程序设计中,在DML和事务控制的语句中可以直接使用SQL,但是DDL语句及系统控制语句却不能在PL/SQL中直接使用,要想实现在PL/SQL中使用DDL语句及系统控制语句,可以通过使用动态SQL来实现。

 

首先我们应该了解什么是动态SQL,在Oracle数据库开发PL/SQL块中我们使用的SQL分为:静态SQL语句和动态SQL语句。所谓静态SQL指在PL/SQL块中使用的SQL语句在编译时是明确的,执行的是确定对象。而动态SQL是指在PL/SQL块编译时SQL语句是不确定的,如根据用户输入的参数的不同而执行不同的操作。编译程序对动态语句部分不进行处理,只是在程序运行时动态地创建语句、对语句进行语法分析并执行该语句。

 

Oracle中动态SQL可以通过本地动态SQL来执行,也可以通过DBMS_SQL包来执行。下面就这两种情况分别进行说明:

 

  一、本地动态SQL

 

本地动态SQL是使用EXECUTE IMMEDIATE语句来实现的。

 

 1、本地动态SQL执行DDL语句:

 

需求:根据用户输入的表名及字段名等参数动态建表。

 

create or replace procedure proc_test

(

     table_name in varchar2,      --表名

     field1 in varchar2,           --字段名

     datatype1 in varchar2,       --字段类型

     field2 in varchar2,           --字段名

     datatype2 in varchar2        --字段类型

) as

     str_sql varchar2(500);

begin

     str_sql:=’create table ’||table_name||’(’||field1||’ ’||datatype1||’,’||field2||’ ’||datatype2||’)’;

    execute immediate str_sql;    --动态执行DDL语句

    exception

        when others then

            null;

end ;

 

以上是编译通过的存储过程代码。下面执行存储过程动态建表。

 

   SQL> execute proc_test(’dinya_test’,’id’,’number(8) not null’,’name’,’varchar2(100)’);

 

PL/SQL procedure successfully completed

 

SQL> desc dinya_test;

Name Type           Nullable Default Comments

---- ------------- -------- ------- --------

ID   NUMBER(8)

 

NAME VARCHAR2(100) Y

 

SQL>

 

到这里,就实现了我们的需求,使用本地动态SQL根据用户输入的表名及字段名、字段类型等参数来实现动态执行DDL语句。

 

  2、本地动态SQL执行DML语句。

 

需求:将用户输入的值插入到上例中建好的dinya_test表中。

 

create or replace procedure proc_insert

(

    id in number,                                  --输入序号

    name in varchar2                              --输入姓名

) as

     str_sql varchar2(500);

begin

     str_sql:=’insert into dinya_test values(:1,:2)’;

    execute immediate str_sql using id,name; --动态执行插入操作

    exception

        when others then

            null;

end ;

 

执行存储过程,插入数据到测试表中。

 

   SQL> execute proc_insert(1,’dinya’);

PL/SQL procedure successfully completed

SQL> select * from dinya_test;

        ID      NAME

         1       dinya

 

在上例中,本地动态SQL执行DML语句时使用了using子句,按顺序将输入的值绑定到变量,如果需要输出参数,可以在执行动态SQL的时候,使用RETURNING INTO 子句,如:

 

declare

     p_id number:=1;

     v_count number;

begin

     v_string:=’select count(*) from table_name a where a.id=:id’;

    execute immediate v_string into v_count using p_id; 

end ;

 

更多的关于动态SQL中关于返回值及为输出输入绑定变量执行参数模式的问题,请读者自行做测试。

 

  二、使用DBMS_SQL

 

使用DBMS_SQL包实现动态SQL的步骤如下:A、先将要执行的SQL语句或一个语句块放到一个字符串变量中。B、使用DBMS_SQL包的parse过程来分析该字符串。C、使用DBMS_SQL包的bind_variable过程来绑定变量。D、使用DBMS_SQL包的execute函数来执行语句。

 

  1、使用DBMS_SQL包执行DDL语句

 

需求:使用DBMS_SQL包根据用户输入的表名、字段名及字段类型建表。

 

create or replace procedure proc_dbms_sql

(

     table_name in varchar2,        --表名

     field_name1 in varchar2,       --字段名

     datatype1 in varchar2,         --字段类型

     field_name2 in varchar2,       --字段名

     datatype2 in varchar2          --字段类型

)as

     v_cursor number;               --定义光标

     v_string varchar2(200);       --定义字符串变量

     v_row number;                   --行数

begin

     v_cursor:=dbms_sql.open_cursor;      --为处理打开光标

     v_string:=’create table ’||table_name||’(’||field_name1||’ ’||datatype1||’,’||field_name2||’ ’||datatype2||’)’;

     dbms_sql.parse(v_cursor,v_string,dbms_sql.native);     --分析语句

     v_row:=dbms_sql.execute(v_cursor);    --执行语句

     dbms_sql.close_cursor(v_cursor);      --关闭光标

    exception

        when others then

             dbms_sql.close_cursor(v_cursor);   --关闭光标

            raise;

end;

 

以上过程编译通过后,执行过程创建表结构:

 

SQL> execute proc_dbms_sql(’dinya_test2’,’id’,’number(8) not null’,’name’,’varchar2(100)’);

 

PL/SQL procedure successfully completed

 

SQL> desc dinya_test2;

Name Type           Nullable Default Comments

---- ------------- -------- ------- --------

ID   NUMBER(8)                              

NAME VARCHAR2(100) Y                        

 

SQL>

 

  2、使用DBMS_SQL包执行DML语句

 

需求:使用DBMS_SQL包根据用户输入的值更新表中相对应的记录。

 

查看表中已有记录:

 

SQL> select * from dinya_test2;

       ID NAME

         1 Oracle

         2 CSDN

         3 ERP

SQL>

 

建存储过程,并编译通过:

 

create or replace procedure proc_dbms_sql_update

(

    id number,

    name varchar2

)as

     v_cursor number;             --定义光标

     v_string varchar2(200);    --字符串变量

     v_row number;                --行数

begin

     v_cursor:=dbms_sql.open_cursor;     --为处理打开光标

     v_string:=’update dinya_test2 a set a.name=:p_name where a.id=:p_id’;

     dbms_sql.parse(v_cursor,v_string,dbms_sql.native);    --分析语句

     dbms_sql.bind_variable(v_cursor,:p_name,name);      --绑定变量

     dbms_sql.bind_variable(v_cursor,:p_id,id);           --绑定变量

     v_row:=dbms_sql.execute(v_cursor);           --执行动态SQL

     dbms_sql.close_cursor(v_cursor);                         --关闭光标

    exception

        when others then

             dbms_sql.close_cursor(v_cursor);                 --关闭光标

            raise;

end;

 

执行过程,根据用户输入的参数更新表中的数据:

 

SQL> execute proc_dbms_sql_update(2,’csdn_dinya’);

 

PL/SQL procedure successfully completed

 

SQL> select * from dinya_test2;

       ID NAME

         1 Oracle

         2 csdn_dinya

         3 ERP

SQL>

 

执行过程后将第二条的name字段的数据更新为新值csdn_dinya。这样就完成了使用dbms_sql包来执行DML语句的功能。

 

使用DBMS_SQL中,如果要执行的动态语句不是查询语句,使用DBMS_SQL.ExecuteDBMS_SQL.Variable_Value来执行,如果要执行动态语句是查询语句,则要使用DBMS_SQL.define_column定义输出变量,然后使用DBMS_SQL.Execute, DBMS_SQL.Fetch_Rows, DBMS_SQL.Column_ValueDBMS_SQL.Variable_Value来执行查询并得到结果。

 

  总结说明:

 

Oracle开发过程中,我们可以使用动态SQL来执行DDL语句、DML语句、事务控制语句及系统控制语句。但是需要注意的是,PL/SQL块中使用动态SQL执行DDL语句的时候与别的不同,在DDL中使用绑定变量是非法的(bind_variable(v_cursor,:p_name,name)),分析后不需要执行DBMS_SQL.Bind_Variable,直接将输入的变量加到字符串中即可。另外,DDL是在调用DBMS_SQL.PARSE时执行的,所以DBMS_SQL.EXECUTE也可以不用,即在上例中的v_row:=dbms_sql.execute(v_cursor)部分可以不要。 更多内容请看PL/SQL  Wlan组网----家庭专题专题,或进入讨论组讨论。

Oracle中动态SQL详解

1.静态SQLSQL与动态SQL

  Oracle编译PL/SQL程序两个:其一前期联编earlybinding),即SQL句在程序编译就已确定,大多数的编译情况属于这种类型;另外一是后期联编latebinding),即SQL句只有在运行段才能建立,例如当查询条件户输,那OracleSQL引擎就无法在编译对该程序行确定,只能在用户输入一定的查询条件后才能提交SQL引擎理。通常,静SQL采用前一种编译方式,而动态SQL采用后一种编译方式。

  本文主要就动态SQL开发进讨论,并在最后出一些实际开发的技巧。

2动态SQL程序开发

  理解了动态SQL编译的原理,也就掌握了其基本的开发思想。动态SQL既然是一不确定SQL,那其行就有其相的特点。Oracle中提供了Executeimmediate句来动态SQL法如下:

   
   
   
   
Excute immediate 动态SQL语句 using 绑定参数列表 returning into 输出参数列表;
对这 句作如下 明:

   1) 动态 SQL 是指 DDL 和不确定的 DML (即 参数的 DML

   2) 定参数列表 为输 入参数列表,即其 in 型,在运行 刻与 动态 SQL 句中的参数( 实际 上占位符,可以理解 函数里面的形式参数) 定。

   3) 出参数列表 为动态 SQL 行后返 回的参数列表。

   4) 由于 动态 SQL 是在运行 行确定的,所以相 于静 而言,其更多的会 失一些系 性能来 取其灵活性。   了更好的 明其 开发 程,下面列 一个 例:

   数据 emp 表,其数据 如下:

ID

NAME

SALARY

100

Jacky

5600

101

Rose

3000

102

John

4500

要求:

  1表并入相的数据。

  2.根据特定ID可以查询到其姓名和薪水的信息。

  3.根据大于特定的薪水的查询工信息。

  根据前面的要求,可以分别创建三个程(均使用动态SQL)来实现

 程一:

复制代码
   
   
   
   
create or replace procedure create_table as begin execute immediate ' create table emp(id number, name varchar2(10), salary number ) ' ; -- 动态SQL为DDL语句 insert into emp values ( 100 , ' jacky ' , 5600 ); insert into emp values ( 101 , ' rose ' , 3000 ); insert into emp values ( 102 , ' john ' , 4500 ); end create_table;
复制代码

程二:

复制代码
   
   
   
   
create or replace procedure find_info(p_id number ) as v_name varchar2 ( 10 ); v_salary number ; begin execute immediate ' select name,salary from emp where id=:1 ' using p_id returning into v_name,v_salary; -- 动态SQL为查询语句 dbms_output.put_line(v_name || ' 的收入为: ' || to_char(v_salary)); exception when others then dbms_output.put_line( ' 找不到相应数据 ' ); end find_info;
复制代码
  程三:

复制代码
   
   
   
   
create or replace procedure find_emp(p_salary number ) as r_emp emp % rowtype; type c_type is ref cursor ; c1 c_type; begin open c1 for ' select * from emp where salary >:1 ' using p_salary; loop fetch c1 into r_emp; exit when c1 % notfound; dbms_output.put_line( ' 薪水大于‘||to_char(p_salary)||’的员工为:‘); dbms_output.put_line( ' ID为 ' to_char(r_emp)|| ' 其姓名为: ' ||r_emp.name); end loop; close c1; end create_table;
复制代码
注意:在 程二中的 动态 SQL 句使用了占位符 “:1“ ,其 它相当于函数的形式参数,使用 ,然后使用 using 句将 p_id 在运行 刻将 :1 掉, p_id 相当于函数里的 参。另外 程三中打 的游 标为动态 ,它也属于 动态 SQL 的范畴,其整个 编译 开发 程与 executeimmediate 行的 程很 似, 里就不在 述了

3动态SQL开发技巧

  前面分析到了,动态SQL行是以失系性能来取其灵活性的,所以行一定程度的化也是必要的,笔者根据实际开发经验给出一些开发的技巧,需要指出的是,里很多经验局限于动态SQL,有些也适用于静SQL,在描述中会注。

  技巧一:尽量使用似的SQL句,这样Oracle本身通SGA中的共享池来直接对该SQL存,那在下一次就直接存中已解析句,以此来提高行效率。

  技巧二:当及到集合元的,尽量使用批联编。比如需要id100101工的薪水加薪10%,一般情况下应该为如下形式:

复制代码
   
   
   
   
declare type num_list is varray( 20 ) of number ; v_id num_list : = num_list( 100 , 101 ); begin ... for i in v_id.first .. v_id.last loop ... execute immediate ' update emp set =salary*1.2 where id=:1 ' using v_id(i); end loop; end ;
复制代码
  于上面的 理,当数据量大的 候就会 得比 慢,那 如果采用批 联编 整个集合首先一次性的 入到 SQL 引擎中 理, 这样 理效率要高的多, 行批 联编处 理的代 如下:

复制代码
   
   
   
   
declare type num_list is varray( 20 ) of number ; v_id num_list : = num_list( 100 , 101 ); begin ... forall i in v_id.first .. v_id.last loop ... execute immediate ' update emp set =salary*1.2 where id=:1 ' using v_id(i); end loop; end ;
复制代码
里是使用 forall 行批 联编 里将批 联编处 理的情形作一个小

   1) 如果一个循 行了 insert delete update 句引用了集合元素,那 可以将其移 到一个 forall 句中。

   2) 如果 select into fetchinto returning into 子句引用了一个集合, 应该 使用 bulkcollect 子句 行合并。

   3) 如有可能, 应该 使用主机数 实现 在程序和数据 器之 间传递 参数。

  技巧三:使用 NOCOPY 编译 器来提高 PL/SQL 性能。缺省情况下, out 型和 inout 型的参数是由 值传递 的方式 行的。但是 于大的 型或者集合 型的参数 传递 而言,其希望 耗将是很大的, 了减少 耗,可以采用引用 传递 的方式,即在 行参数声明的 候引用 NOCOPY 关键 字来 明即可到达 这样 的效果。 比如 建一个 程:

   
   
   
   
create or replace procedure test(p_object in nocopy square ) ... end ;
其中 square 一个大的 型。 这样 只是 传递 一个地址,而不是 传递 整个 象了。 这样 理也是提高了效率。

   4

  本文 对动态 SQL 编译 原理、 开发过 程以及 开发 技巧的 讨论 ,通 本文的介 后,相信 对动态 SQL 程序 开发 有了一个 体的 认识 今后深入的工作打下一个良好的基

1、静态SQL语句性能优于动态SQL语句,如果功能确定最好使用静态SQL语句

2、使用execute immediate语句,用于处理除了多行查询之外的任何动态SQL,包括DDL、DCL、DML、以及单行Select语句

3、使用动态引用游标OPEN-FOR、FETCH、CLOSE语句处理多行查询语句

4、使用批量的动态SQL语句,可以提高pl/sql性能

一、处理DDL语句

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     v_sql varchar2(2000);  
  4.   begin  
  5.     v_sql:='create table test as select * from dept';  
  6.     execute immediate v_sql;  
  7.   end;  
  8. end;  


二、处理DCL语句

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     v_sql varchar2(2000);  
  4.   begin  
  5.     v_sql:='grant select on test to user_01';  
  6.     execute immediate v_sql;  
  7.   end;  
  8. end;  


三、处理DML语句

根据DML语句是否有占位符、是否是returning子句处理方式不同

1、处理无占位符和returning子句的DML语句

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     v_sql varchar2(2000);  
  4.   begin  
  5.     v_sql:='update test set loc=''HELLOWORLD'' where deptno=10';  
  6.     execute immediate v_sql;  
  7.   end;  
  8. end;  


2、处理有占位符无returning子句的DML语句

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     v_sql varchar2(2000);  
  4.   begin  
  5.     v_sql:='update test set loc=:loc where deptno=:deptno';  
  6.     execute immediate v_sql using &1,&2;  
  7.   end;  
  8. end;  


3、处理无占位符有returning子句的DML语句

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     v_sql varchar2(2000);  
  4.     v_dname dept.dname%type;  
  5.   begin  
  6.     v_sql:='update test set loc=''HELLOWORLD'' where deptno=10 returning dname into :name';  
  7.     execute immediate v_sql returning into v_dname;  
  8.     dbms_output.put_line(v_dname||'被更新');        
  9.   end;  
  10. end;  


4、处理含占位符有returning子句的DML语句

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     v_sql varchar2(2000);  
  4.     v_dname dept.dname%type;  
  5.   begin  
  6.     v_sql:='update test set loc=''HELLOWORLD'' where deptno=:deptno returning dname into :name';  
  7.     execute immediate  v_sql using &deptno returning into v_dname;  
  8.     dbms_output.put_line(v_dname||'被更新');        
  9.   end;  
  10. end;  


四、处理单行查询

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     v_sql varchar2(2000);  
  4.     v_record dept%rowtype;  
  5.   begin  
  6.     v_sql:='select * from dept where deptno=:deptno';  
  7.     execute immediate v_sql into v_record using &deptno ;  
  8.     dbms_output.put_line('部门名称:'||v_record.dname);        
  9.   end;  
  10. end;  


通过记录变量来获取数据

五、处理多行查询

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     type dept_cur is ref cursor;  
  4.     c_dept dept_cur;  
  5.     v_sql varchar2(2000);  
  6.     v_record dept%rowtype;  
  7.   begin  
  8.     v_sql:='select * from dept where deptno=:deptno';  
  9.     open c_dept for v_sql using &deptno;  
  10.     loop  
  11.       fetch c_dept into v_record;  
  12.       exit when c_dept%NOTFOUND;  
  13.       dbms_output.put_line('部门名称:'||v_record.dname);        
  14.     end loop;  
  15.     close c_dept;      
  16.   end;  
  17. end;  


六、在动态SQL语句中使用批量绑定

在动态SQL语句中使用批量绑定,可以加快批量数据的处理速度,提高性能;

当使用批量绑定时,集合元素要使用SQL的数据类型而非PL/SQL数据类型,最好通过%TYPE,%ROWTYPE来

(1)、在动态DML语句上面使用批量绑定

语法:

[sql] view plain copy
  1. FORALL index IN 1..v_tab.count  
  2.      execute immediate v_sql using v_tab(i);  


举例:

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     type dept_var is varray(3) of dept.deptno%type;  
  4.     v_dept dept_var;  
  5.     v_sql varchar2(2000);      
  6.   begin  
  7.     v_dept:=dept_var(1,2,3);  
  8.     v_sql:='update dept set loc=''测试数据'' where deptno=:deptno';      
  9.     forall i IN 1..v_dept.count  
  10.       execute immediate v_sql using v_dept(i) ;      
  11.   end;  
  12. end;  


(2)、在DML返回子句上使用批量绑定

语法:

[sql] view plain copy
  1. execute immediate v_sql  
  2.    returning bulk collect into v_coll;  


举例:

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     type dname_tab is table of dept.dname%type;  
  4.     v_name dname_tab;  
  5.     type loc_tab is table of dept.loc%type;  
  6.     v_loc loc_tab;  
  7.     v_sql varchar2(2000);      
  8.   begin      
  9.     v_sql:='update dept set loc=''测试数据DDDDD'' where deptno=:deptno returning dname,loc into :1,:2';         
  10.     execute immediate v_sql using &deptno returning bulk collect into v_name,v_loc;      
  11.     for i IN 1..v_name.count loop  
  12.       dbms_output.put_line('部门名称:'||v_name(i)||'  地址:'||v_loc(i));        
  13.     end loop;  
  14.   end;  
  15. end;  


(3)、在execute immediate语句上使用批量绑定查询语句

语法:

[sql] view plain copy
  1. execute immediate v_sql bulk collect into v_coll;  


举例:

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     type dname_tab is table of dept.dname%type;  
  4.     v_name dname_tab;  
  5.     type loc_tab is table of dept.loc%type;  
  6.     v_loc loc_tab;  
  7.     v_sql varchar2(2000);      
  8.   begin      
  9.     v_sql:='select dname,loc from dept where deptno=:deptno';         
  10.     execute immediate v_sql bulk collect into v_name,v_loc using &deptno;      
  11.     for i IN 1..v_name.count loop  
  12.       dbms_output.put_line('部门名称:'||v_name(i)||'  地址:'||v_loc(i));        
  13.     end loop;  
  14.   end;  
  15. end;  

(4)、在游标FETCH语句中使用批量提取

语法:

[sql] view plain copy
  1. fetch v_cursor bulk collect into v_coll;  


举例:

[sql] view plain copy
  1. begin  
  2.   declare  
  3.     type c_ref is ref cursor;  
  4.     c_dept c_ref;  
  5.     type dname_tab is table of dept.dname%type;  
  6.     v_name dname_tab;  
  7.     type loc_tab is table of dept.loc%type;  
  8.     v_loc loc_tab;  
  9.     v_sql varchar2(2000);      
  10.   begin      
  11.     v_sql:='select dname,loc from dept where deptno=:deptno';    
  12.     open c_dept for v_sql using &deptno;  
  13.     fetch c_dept bulk collect into v_name,v_loc;  
  14.     close c_dept;  
  15.       
  16.     for i IN 1..v_name.count loop  
  17.       dbms_output.put_line('部门名称:'||v_name(i)||'  地址:'||v_loc(i));        
  18.     end loop;      
  19.   end;  
  20. end

你可能感兴趣的:(oracle,动态语句)