【问题标题】:PL/SQL - execute immediate in pipelined functionPL/SQL - 在流水线函数中立即执行
【发布时间】:2012-09-16 17:33:54
【问题描述】:

我想在我的流水线函数中执行动态查询并返回此查询的结果。 是否有可能做到这一点? 流水线函数方便我为我的应用程序实现良好的接口,因为它的行为就像一个表格。

功能:

CREATE OR REPLACE FUNCTION MyFunction(p_schema VARCHAR2) RETURN MyTableType Pipelined IS
v_query VARCHAR2(1000);
BEGIN
  v_query := 'SELECT * FROM TABLE ('||p_schema||'.somepackage.SomeFunction)'; --SomeFunction is another pipelined function
  EXECUTE IMMEDIATE v_query;
  --Results of the v_query are compatible with MyTableType's row type. But how to return them from pipelined function?
END;

【问题讨论】:

    标签: oracle plsql execute-immediate pipelined-function


    【解决方案1】:

    我无法得到@VincentMalgrat 的回答。但它非常接近。对我来说,这绝对是朝着正确方向迈出的一大步。

    这是我要工作的内容:

     CREATE OR REPLACE PACKAGE pkg AS
         TYPE test_row IS RECORD  ( test_name  VARCHAR2 (255), test_number number, test_date date );  
         TYPE test_tab IS TABLE OF test_row;
         FUNCTION dynamic_cursor(l_where VARCHAR2) RETURN test_tab PIPELINED;
       END;
    

    包体

     CREATE OR REPLACE PACKAGE BODY pkg IS
         FUNCTION dynamic_cursor(l_where VARCHAR2) RETURN test_tab PIPELINED IS
            cc sys_refcursor;
            l_row test_row;
         BEGIN
            OPEN cc FOR 'select name_column, number_column, date_column FROM my_table where number_column ='||l_where;
            LOOP
               FETCH cc INTO l_row;
               EXIT WHEN cc%NOTFOUND;
               PIPE ROW (l_row);
            END LOOP;
            RETURN;
         END;
      END;
    

    【讨论】:

      【解决方案2】:

      可以结合动态 SQL 和流水线函数,但返回类型不会是动态的:返回的列的数量和类型是固定的。

      您可以使用EXECUTE IMMEDIATEBULK COLLECT(感谢@be here now)、dynamic cursorsDBMS_SQL 来返回多行。这是一个带有动态光标的示例:

      SQL> CREATE OR REPLACE PACKAGE pkg AS
        2     TYPE test_tab IS TABLE OF test%ROWTYPE;
        3     FUNCTION dynamic_cursor(l_where VARCHAR2) RETURN test_tab PIPELINED;
        4  END;
        5  /
      
      Package created.
      
      SQL> CREATE OR REPLACE PACKAGE BODY pkg IS
        2     FUNCTION dynamic_cursor(l_where VARCHAR2) RETURN test_tab PIPELINED IS
        3        cc sys_refcursor;
        4        l_row test%ROWTYPE;
        5     BEGIN
        6        OPEN cc FOR 'SELECT * FROM test WHERE ' || l_where;
        7        LOOP
        8           FETCH cc INTO l_row;
        9           EXIT WHEN cc%NOTFOUND;
       10           PIPE ROW (l_row);
       11        END LOOP;
       12        RETURN;
       13     END;
       14  END;
       15  /
      
      Package body created.
      

      我们称之为动态函数:

      SQL> SELECT *
        2    FROM TABLE(pkg.dynamic_cursor('id <= 2'));
      
              ID DAT
      ---------- ---
               1 xxx
               2 xxx
      

      与动态 SQL 一样,请注意SQL Injection

      【讨论】:

      • @dzb: DBMS_SQL 不会让查询变快 :),实际上比原生动态 SQL 的开销要多一些。您的查询可能很慢的原因有很多,以至于我无法预测如何在如此少的上下文中提高其性能。动态 SQL 和静态 SQL 之间的唯一区别是变量的使用。你用parameterized dynamic SQL吗?
      • 感谢这个例子。它的工作,但可怕的缓慢。我认为这是因为我在查询中调用了另一个流水线函数(我更新了我的问题),看起来它被调用了太多次。您能否向 dbms_sql 提出一些建议?
      • @VincentMalgrat execute immediate ... bulk collect into ...; for i in col.first .. col.last loop pipe row () end loop; ?
      • @dzb:原来的流水线函数比包装函数快吗?
      • @beherenow 你是对的,我的错。出于某种原因,我认为您不能将BULK COLLECT%ROWTYPE 的表一起使用。但它不仅有效,而且对于小型套装会更快:)
      【解决方案3】:

      我认为是这样的:

      CREATE OR REPLACE FUNCTION MyFunction(par1 VARCHAR2, ...) RETURN MyTableType Pipelined IS
      v_query VARCHAR2(1000);
      l_result MyTableType;
      BEGIN
        v_query := --My query created based on parameters
        EXECUTE IMMEDIATE v_query into l_result;
      
        pipe row(l_result);
      END;
      

      仅当 v_query 返回 1 行时才有效。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-26
        • 2017-02-14
        • 1970-01-01
        • 2023-03-31
        • 2018-02-25
        相关资源
        最近更新 更多