1. 程式人生 >實用技巧 >其它 >Oracle:動態sql

Oracle:動態sql


一、概述
二、執行ddl、dcl語句
三、處理dml語句
1、給動態語句傳值(USING 子句)
2、從動態語句檢索值(INTO子句)
3、動態呼叫儲存過程
4、處理包含returing子句的DML語句
5、在retuing into中使用bulk collect into
四、處理多行查詢
1、使用動態遊標(遊標變數)處理多行查詢類動態sql語句
2、在execute immediate中使用bulk collect into
3、在forall語句中使用bulk collect into語句



一、概述

在一般的sql操作中,sql語句基本上都是固定的,如: SELECT t.empno,t.ename FROM scott.emp t WHERE t.deptno = 20; 但有的時候,從應用的需要或程式的編寫出發,都可能需要用到動態SQl,如: 當 from 後的表 不確定時,或者where 後的條件不確定時,都需要用到動態SQL。

使用execute immediate語句可以處理包括ddl(create、alter和drop)、DCL(grant、revoke)、DML(insert、update、delete)以及單行select語句。

execute immediate語句:

execute immediate 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返回值的變數。


二、執行ddl、dcl語句

不能使用into和using子句
begin
execute immediate 'create table ma_org(org_codevarchar2(20),org_name varchar2(254))';
execute immediate 'drop table ma_org';
end;

語句

begin
       execute immediate 'grant insert on ma_org to scott'
end;

三、處理dml語句

1、給動態語句傳值(USING 子句)

如果dml語句包含佔位符,那麼在execute immediate語句之後必須要帶有using子句;
declare
         orgcode varchar2(10);
         orgname varchar2(254);
    begin
         orgcode := 1200;
         execute immediate 'select org_name fromma_org 
         where org_code = :X'
         into orgname
         using orgcode; 
         dbms_output.put_line(orgname);
    end;

2、從動態語句檢索值(INTO子句)

Oracle:動態sql


3、動態呼叫儲存過程

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 out l_status;

  if l_status != 'OK' then
     dbms_output.put_line('error');
  end if;
end;

4、處理包含returing子句的DML語句

如果dml語句帶有returning子句,那麼在execute immediate語句之後必須帶有returning into子句,並且此時只能處理作用的單行上的dml語句,如果dml語句作用在多行上,則必須使用bulk子句。
declare
         orgcode varchar2(10);
         orgname varchar2(254);
         rname varchar2(254);
    begin
         orgcode := '1200';
         orgname := '天津市分行';
         execute immediate 'update ma_org set org_name=:X 
         where org_code = :Y returning org_name into :rname'
         using orgname, orgcode
         returning into rname; 
         dbms_output.put_line(orgname);
    end;

5、在retuing into中使用bulk collect into

Oracle:動態sql


四、處理多行查詢

oracle通過使用bulk collect into子句處理動態sql中的多行查詢可以加快處理速度,從而提高應用程式的效能。當使用bulk子句時,集合型別可以是plsql所支援的索引表、巢狀表和varray,但集合元素必須使用sql資料型別。在oracle9i以後,有三種語句支援bulk子句,execute immediate,fetch和forall。

1、使用動態遊標(遊標變數)處理多行查詢類動態sql語句

DECLARE
    TYPE ref_cur IS REF CURSOR;
    rc ref_cur;
    emprow emp%ROWTYPE;
    v_sql VARCHAR2(100):= 'select * from emp where deptno = :x';   --動態執行的SQL語句
BEGIN
    OPEN rc FOR v_sql USING 30;   --開啟遊標,繫結執行的SQL語句,並傳遞引數
  LOOP
        FETCH rc INTO emprow;
        EXIT WHEN rc%NOTFOUND;
        dbms_output.put_line('name:'||emprow.ename||'  sal:'||emprow.sal);
    END LOOP;
    CLOSE rc;
END;

2、在execute immediate中使用bulk collect into

示例1:
declare
         type org_table_type is table of ma_org%rowtype;
         org_table org_table_type;
         v_orgcode varchar2(20);
    begin
         v_orgcode := '%00%';
         execute immediate 'select * from ma_org where org_code like:v_orgcode' bulk collect into org_table
         using v_orgcode;
         for i in 1..org_table.count
             loop    
                dbms_output.put_line(org_table(i).org_code||','||org_table(i).org_name);
             end loop; 
    end;

示例2:

declare
 type org_table_type is table of z_dangan%rowtype  index by binary_integer;
 org_table org_table_type;
 v_orgcode varchar2(200);
begin
 v_orgcode := '%王%';
 execute immediate 'select * from z_dangan where xingming like:v_orgcode' bulk collect into org_table 
   using v_orgcode;
   commit;
   for i in 1..org_table.count loop
   		      dbms_output.put_line(org_table(i).xingming);
    end loop; 
end;

3、在forall語句中使用bulk collect into語句

示例:
declare
         type type_org_code is table of ma_org.org_code%type;
         type type_org_name is table of ma_org.org_name%type;
         v_orgcode type_org_code;
         v_orgname type_org_name;
    begin
         v_orgcode := type_org_code('1100','1200'); 
         forall i in 1..v_orgcode.count
            execute immediate 'update ma_org set org_name = org_code||org_namewhere org_code = :p1 returning org_name into :p2'
            using v_orgcode(i)
            returning bulk collect into v_orgname; 
         for i in v_orgname.first..v_orgname.last

            loop
               dbms_output.put_line(v_orgname(i));
         end loop;
    end;




declare
  type type_org_code is table of z_dangan.danganid%type;
  type type_org_name is table of z_dangan.xingming%type;
  v_orgcode type_org_code;
  v_orgname type_org_name;
  names     varchar(20);
begin
  v_orgcode := type_org_code('000480090000000002', '000480020000000005');
  names     := '測試';
  forall i in 1 .. v_orgcode.count execute immediate
                   'update z_dangan set xingming =:p1 where  danganid =:p2 returning xingming into :p3'
                   using names, v_orgcode(i) returning bulk collect into
                   v_orgname
    ;
  for i in v_orgname.first .. v_orgname.last loop
    dbms_output.put_line(v_orgname(i));
  end loop;
end;