【问题标题】:dynamic sql in a pipeline function oracle管道函数oracle中的动态sql
【发布时间】:2021-06-20 19:49:39
【问题描述】:
create or replace function fn_master(col_name VARCHAR2) return master_file pipelined
Is
       TYPE MYMASTER_FILE IS RECORD (
        id                         NUMBER(5),
        name                        VARCHAR2(101),
        school                      varchar2(2000)
       
   );



 
   TYPE MASTER_FILE_ARRAY IS TABLE OF MYMASTER_FILE
      INDEX BY PLS_INTEGER;
 
   l_info MASTER_FILE_ARRAY;
    
begin 



execute immediate 'select id, name, school from x_table where ' || col_name || '= ''xxxxxx'' ' 

   BULK COLLECT INTO l_info;
 
   FOR i IN 1 .. l_info.COUNT
   LOOP
                              PIPE row(master_file(               
                                    l_info(i).id,
                                    l_info(i).name ,
                                    l_info(i).school
                                  
                                ));
   END LOOP;
end fn_master;

这是我创建的函数,用于接受该表中的列并打印返回的行。为了在堆栈溢出时将其呈现在此处,我将其简化了。

当我尝试编译时出现错误

PLS-00630: pipelined functions must have a supported collection return type

但是当我添加一个返回子句时它告诉我

PLS-00633: RETURN statement in a pipelined function cannot contain an expression
PLS-00382: expression is of wrong type
PLS-00630: pipelined functions must have a supported collection return type

你们能帮我解决这个问题吗

【问题讨论】:

  • 是我接近函数的方式,正确的方式吗?

标签: oracle plsql oracle10g oracle-sqldeveloper oracle18c


【解决方案1】:

您的代码存在一些问题,与返回类型有关,而不是与动态 SQL 的使用有关。

首先,流水线函数的返回类型应该是表类型,而不是行类型。您已将其设置为 master_file。 (顺便说一句,你实际上并没有在任何地方定义过这种类型,但我们不要纠缠于此。也许你的意思是mymaster_file?)

但是,如果您随后将其设置为 master_file_array,则会收到错误 PLS-00498: illegal use of a type before its declaration。在某种程度上,这是有道理的:Oracle 不编译该函数不知道该函数返回什么类型,但它需要知道返回类型才能编译该函数。

因此,让我们定义一个对象类型和一个嵌套表类型,这样我们就可以将其用作返回类型:

CREATE OR REPLACE TYPE MASTER_FILE AS OBJECT (
        id                         NUMBER(5),
        name                       VARCHAR2(101),
        school                     varchar2(2000)
);
/

CREATE TYPE MASTER_FILE_ARRAY AS TABLE OF MASTER_FILE;
/

然后我尝试将这些类型与您的EXECUTE IMMEDIATE 语句的BULK COLLECT INTO 子句一起使用,认为您在函数中声明的类型不再需要了。然而,当我这样做时,我得到了一个非常有用的错误ORA-00932: inconsistent datatypes: expected - got -。看来您只能将 PL/SQL 关联数组(即使用 INDEX BY 子句声明的集合)与 BULK COLLECT INTO 一起使用,所以让我们再次尝试使用您在函数中定义的集合类型:

create or replace function fn_master(col_name VARCHAR2) return master_file_array pipelined
is
  TYPE MYMASTER_FILE IS RECORD (
    id        NUMBER(5),
    name      VARCHAR2(101),
    school    varchar2(2000)
  );
 
  TYPE MYMASTER_FILE_ARRAY IS TABLE OF MYMASTER_FILE
    INDEX BY PLS_INTEGER;
 
  l_info MYMASTER_FILE_ARRAY;

begin 

  execute immediate 'select id, name, school from x_table where ' || col_name || '= ''xxxxxx'' ' BULK COLLECT INTO l_info;
 
  FOR i IN 1 .. l_info.COUNT
  LOOP
    PIPE row(master_file(               
        l_info(i).id,
        l_info(i).name ,
        l_info(i).school
    ));
  END LOOP;
end fn_master;
/

请注意,我使用前缀MY 作为函数内声明的类型的名称。函数中的 PL/SQL 关联数组类型的名称现在是 MYMASTER_FILE_ARRAY,并且 l_info 被声明为这种类型。函数外声明的类型名称没有这个前缀,所以函数返回MASTER_FILE_ARRAY,调用PIPE ROW(...)使用MASTER_FILE

我创建了一个表x_table 并在其中插入了一些数据,在进行上述修改后,我能够调用您的函数并让它从该表中返回一些数据。

【讨论】:

    【解决方案2】:

    流水线函数的要点是能够将一组结果流回调用者,而无需将整个集合实例化为内存中的集合。这意味着您可以在第一行可用时立即开始返回行,而无需等待最后一行或为整个集合分配内存。发布的函数在管道任何东西之前将所有行获取到一个数组中,因此首先将其管道化似乎没有任何意义。

    真正的流水线实现可能如下所示:

    create or replace function fn_master
        ( col_name varchar2 )
        return master_file_array
        pipelined
    as
        c_results sys_refcursor;
        r master_file := master_file(null, null, null);
    begin
        open c_results for 'select id, name, school from demo where ' || col_name || '= ''ABC'' ';
    
        loop
            fetch c_results into r.id, r.name, r.school;
            exit when c_results%notfound;
            pipe row(r);
        end loop;
    end fn_master;
    

    顺便说一句,我建议在代码布局上多加注意,因为它使代码更易于理解、调试和维护。

    【讨论】:

      猜你喜欢
      • 2020-06-02
      • 2014-12-03
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      • 1970-01-01
      • 2016-09-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多