现在的位置: 首页 > 综合 > 正文

用sys_context 和Native Dynamic SQL实现变量绑定

2018年04月17日 ⁄ 综合 ⁄ 共 4610字 ⁄ 字号 评论关闭

假如要实现以下的一个Procedure, 这个procedure动态生成一个where clause,然后运行合成后的查询而获得一些查询信息。create or replace procedure do_query(cname_in    dbms_sql.varchar2_table,
                                     operator_in dbms_sql.Varchar2_Table,
                                     value_in    dbms_sql.Varchar2_Table) 。

有两种方法可以实现: 1)dbms_sql 2)natvie dynamic sql
1>如果用dbms_sql, 优点:可以用bind variable, 很少的soft parse.如果此程序被多人多用户使用,可极大的挺高性能。 缺点: 多去额外的开销。 比native dynamic sql多出很多辅助程序。 实现如下:

    create or replace procedure do_query(cname_in    dbms_sql.varchar2_table,
                                         operator_in dbms_sql.Varchar2_Table,
                                         value_in    dbms_sql.Varchar2_Table) is
      v_cursor   int default dbms_sql.open_cursor;
      v_query    long;
      v_sep      varchar2(20) default 'where ';
      v_colvalue varchar2(4000);
      v_status   integer;
    begin
      v_query := 'select empno,ename,sal from emp ';

      For i in 1..cname_in.count loop
        v_query := v_query || v_sep || cname_in(i) || ' ' || operator_in(i) || ' ' ||
                   ':bv' || i;
        v_sep   := ' and ';
      end loop;

      dbms_sql.parse(v_cursor, v_query, dbms_sql.native);

      For i in 1..cname_in.count loop
        dbms_sql.bind_variable(v_cursor, ':bv' || i, value_in(i));
      end loop;

      for i in 1 .. 3 loop
        dbms_sql.define_column(v_cursor, i, v_colvalue, 4000);
      end loop;

      v_status := dbms_sql.execute(v_cursor);

      while (dbms_sql.fetch_rows(v_cursor) > 0) loop
        for i in 1 .. 3 loop
          dbms_sql.column_value(v_cursor, i, v_colvalue);
          dbms_output.put(v_colvalue || '--------');
        end loop;
        dbms_output.new_line;
      end loop;
    end;

    16:45:37 lab@ORCL>declare
    17:06:26   2  v_cname dbms_sql.varchar2_table;
    17:06:26   3  v_operator dbms_sql.varchar2_table;
    17:06:26   4  v_value dbms_sql.varchar2_table;
    17:06:26   5  begin
    17:06:26   6  v_cname(1) :='ename';
    17:06:26   7  v_cname(2) :='deptno';
    17:06:26   8
    17:06:26   9  v_operator(1) :=' like ';
    17:06:26  10  v_operator(2) :=' = ';
    17:06:26  11
    17:06:26  12  v_value(1) := '%A%';
    17:06:26  13  v_value(2) := '40';
    17:06:26  14
    17:06:26  15  do_query(v_cname,v_operator,v_value);
    17:06:27  16  end;
    17:06:27  17  /
    7599--------ALLEN--------1700--------
    7621--------WARD--------1350--------
    7754--------MARTIN--------1350--------
    7798--------BLAKE--------2950--------
    8000--------JAMES--------1050--------

    PL/SQL 过程已成功完成。

    已用时间:  00: 00: 00.03

    2>如果用Native Dynamic SQL则有相反的优缺点。不过最大的问题的是: Native Dynamic SQL只能以实际值来拼成一个可执行的sql, 不能使用绑定变量。 Oracle介绍了特性可以帮助解决这一难点: Sys_context;
    那么首先来了解一下Sys_context的用法。

      17:53:02 sys@ORCL>grant create any context to lab;

      授权成功。

      已用时间:  00: 00: 00.01
      17:53:38 sys@ORCL>conn lab/lab;
      已连接。
      17:53:49 lab@ORCL>create or replace context bv_context using dyn_demo;

      上下文已创建。

      已用时间:  00: 00: 00.06

      create or replace package dyn_demo
      is
      procedure do_query2(cname_in    dbms_sql.varchar2_table,
                                            operator_in dbms_sql.Varchar2_Table,
                                            value_in    dbms_sql.Varchar2_Table);
      end dyn_demo;

      create or replace package body dyn_demo
      is
      procedure do_query2(cname_in    dbms_sql.varchar2_table,
                                            operator_in dbms_sql.Varchar2_Table,
                                            value_in    dbms_sql.Varchar2_Table) is
        type rc is ref cursor;
        v_cursor rc;

        v_query long;
        v_sep   varchar2(20) default 'where ';
        v_empno emp.empno%type;
        v_ename emp.ename%type;
        v_sal   emp.sal%type;
      begin
        v_query := 'select empno,ename,sal from emp ';

        For i in 1 .. cname_in.count loop
          v_query := v_query || v_sep || cname_in(i) || ' ' || operator_in(i) || ' ' ||
                     'sys_context(''BV_CONTEXT'',''' || cname_in(i) || ''')';
          dbms_session.set_context('bv_context',cname_in(i),value_in(i));
          v_sep   := ' and ';
        end loop;

        open v_cursor for v_query;
        loop
          fetch v_cursor
            into v_empno, v_ename, v_sal;
          exit when v_cursor%notfound;
          dbms_output.put_line(v_empno || '--------' || v_ename || '--------' ||
                               v_sal || '--------');
        end loop;
        close v_cursor;
      end do_query2;

      begin
      null;
      end dyn_demo;

      --sample data
      18:05:37 lab@ORCL>declare
      18:09:05   2  v_cname dbms_sql.varchar2_table;
      18:09:05   3  v_operator dbms_sql.varchar2_table;
      18:09:05   4  v_value dbms_sql.varchar2_table;
      18:09:05   5  begin
      18:09:05   6  v_cname(1) :='ename';
      18:09:05   7  v_cname(2) :='deptno';
      18:09:05   8
      18:09:05   9  v_operator(1) :=' like ';
      18:09:05  10  v_operator(2) :=' = ';
      18:09:05  11
      18:09:05  12  v_value(1) := '%A%';
      18:09:05  13  v_value(2) := '40';
      18:09:05  14
      18:09:05  15  dyn_demo.do_query2(v_cname,v_operator,v_value);
      18:09:05  16  end;
      18:09:05  17  /
      7599--------ALLEN--------1700--------
      7621--------WARD--------1350--------
      7754--------MARTIN--------1350--------
      7798--------BLAKE--------2950--------
      8000--------JAMES--------1050--------

      PL/SQL ????????

      ????:  00: 00: 00.01

       

      综上所述, dynamic SQL相对于静态sql来讲提供更多的扩展性。 但是效率相对低。 此外还有三大缺点:

      1. 破坏了对象之间的依赖关系;
      2. 使程序变得更脆弱;
      3. 使程序更难被调试。

      那么dbms_sql和NDS(Native Dynamic SQL)相比:

      1. dbms_sql使用绑定变量,适用于被经常或大量使用的程序。 此时效率高;但代码量更大。在绑定变量个数未知, 输出变量个数未知的情况下应用dbms_sql.
      2. NDS代码量小, 在使用次数少的时候能减少工作量. 此时运行速度快。 有时要搭档open for(ref cursor)使用。

        抱歉!评论已关闭.