【问题标题】:Difference between EXEC_SQL, EXECUTE IMMEDIATE, DBMS_SQL and inline SQLEXEC_SQL、EXECUTE IMMEDIATE、DBMS_SQL 和内联 SQL 之间的区别
【发布时间】:2015-07-11 00:17:58
【问题描述】:

我一直在研究一些 PL/SQL(在 Oracle SQL Developer 中),并且看到了几种不同格式的 SQL 被调用。

为了当前和未来代码的一致性和速度,我想知道哪个是首选。

我见过的有四种。

1) 普通 DDL:

CREATE TABLE newtable AS SELECT * FROM pSource;

2) 立即执行(本机动态 SQL):

statement := 'CREATE TABLE newtable AS SELECT * FROM ' || pSource;
EXECUTE IMMEDIATE statement;

3) EXEC_SQL:

EXEC_SQL('CREATE TABLE newtable AS SELECT * FROM ' || pSource);

4) DBMS_SQL:

cursor := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(cursor, 'CREATE TABLE newtable AS SELECT * FROM ' || pSource, DBMS_SQL.NATIVE);
numRows := DBMS_SQL.EXECUTE(cursor);

这些不同的调用方式之间有什么特别的优点/缺点/限制吗?

【问题讨论】:

    标签: oracle plsql oracle-sqldeveloper execute-immediate


    【解决方案1】:

    1) 不能在 PL/SQL 块内直接执行 DDL。

    BEGIN
       CREATE TABLE TEST AS (
          SELECT * FROM FND_USER
        );
      EXCEPTION
        WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE(SQLERRM);
    END;
    /
    

    产量:

    PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
    

    2) EXECUTE IMMEDIATE(及其姐妹DBMS_SQL)用于在 PL/SQL 块内执行 SQL。这些与“常规”SQL 的不同之处在于它们实际上使用完全不同的 SQL 引擎(在 PL/SQL 的情况下,它在oracle 进程中运行)进行计算。这就是为什么我们这么多人宣扬“如果你能在 SQL 中做到这一点,就不要在 PL/SQL 中做到这一点”。
    甚至这两个选项也有所不同。 EXECUTE IMMEDIATE 快速简单,但有点愚蠢。 DBMS_SQL 稍微复杂一些,但为开发人员提供了更多控制权。
    例如,这个例子本质上描述了一个表的列:

    declare
      c number;
      d number;
      col_cnt integer;
      f boolean;
      rec_tab dbms_sql.desc_tab;
      col_num number;
      procedure print_rec(rec in dbms_sql.desc_rec) is
      begin
        dbms_output.new_line;
        dbms_output.put_line('col_type            =    '
                             || rec.col_type);
        dbms_output.put_line('col_maxlen          =    '
                             || rec.col_max_len);
        dbms_output.put_line('col_name            =    '
                             || rec.col_name);
        dbms_output.put_line('col_name_len        =    '
                             || rec.col_name_len);
        dbms_output.put_line('col_schema_name     =    '
                             || rec.col_schema_name);
        dbms_output.put_line('col_schema_name_len =    '
                             || rec.col_schema_name_len);
        dbms_output.put_line('col_precision       =    '
                             || rec.col_precision);
        dbms_output.put_line('col_scale           =    '
                             || rec.col_scale);
        dbms_output.put('col_null_ok         =    ');
        if (rec.col_null_ok) then
          dbms_output.put_line('true');
        else
          dbms_output.put_line('false');
        end if;
      end;
    begin
      c := dbms_sql.open_cursor;
    
      dbms_sql.parse(c, 'select * from fnd_user', dbms_sql.native);
    
      d := dbms_sql.execute(c);
    
      dbms_sql.describe_columns(c, col_cnt, rec_tab);
    
    /*
     * Following loop could simply be for j in 1..col_cnt loop.
     * Here we are simply illustrating some of the PL/SQL table
     * features.
     */
      col_num := rec_tab.first;
      if (col_num is not null) then
        loop
          print_rec(rec_tab(col_num));
          col_num := rec_tab.next(col_num);
          exit when (col_num is null);
        end loop;
      end if;
    
      dbms_sql.close_cursor(c);
    end;
    /
    

    Source
    由于DBMS_SQL 允许我们打开和操作PL/SQL 块在其中运行的游标,因此在EXECUTE IMMEDIATE 块中很难重现结果内部(难度级别:不能从ALL_TAB_COLS 中选择,这只是旨在提供信息:)。

    3)EXEC_SQL 是上述DBMS_SQL 的表单特定版本。明智地使用它。 :)

    Here 是对上述内容的一个很好的分解,here 是 Tom Kyte 尽他所能分解它。

    【讨论】:

    • 谢谢。我认为我误认为是直接看到 SQL。我看到的内联是这样的:CURSOR cur IS SELECT table_name FROM cols 和这个SELECT table_name FROM cols INTO types。我认为这意味着任何 SQL 都可以这样完成。
    猜你喜欢
    • 2020-07-14
    • 2021-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-01
    • 2011-10-21
    • 2014-07-11
    • 1970-01-01
    相关资源
    最近更新 更多