ORA-06504: PL/SQL: 执行时返回结果集变量的类型

Posted

技术标签:

【中文标题】ORA-06504: PL/SQL: 执行时返回结果集变量的类型【英文标题】:ORA-06504: PL/SQL: Return types of Result Set variables while execution 【发布时间】:2017-08-21 13:45:35 【问题描述】:

我创建了一个如下的对象和过程,执行时出现以下错误。

ORA-06504:PL/SQL:返回结果集变量或查询的类型 不匹配 ORA-06512:在第 8 行

CREATE OR REPLACE TYPE OBJ_TST AS OBJECT
(
   COl_ID NUMBER (30, 0),
   Col_DATE TIMESTAMP (6)
);
/

create or replace TYPE OBJ_TBL AS TABLE OF OBJ_TST;

/

CREATE OR REPLACE PROCEDURE TST_OBJ  (input_date IN     DATE,
                                      out_cur     OUT SYS_REFCURSOR )                                    
AS   
   l_tab    OBJ_TBL  := OBJ_TBL ();
BEGIN

   SELECT OBJ_TST (ti.col_id, ti.col_date)
     BULK COLLECT INTO l_tab
     FROM MY_TBL ti
    WHERE ti.create_date BETWEEN input_date AND input_date + 1;

   Open o_cur for select col_id,col_date from table(l_tab);

END TST_OBJ;
/

执行给我带来了上述错误。 MY_TBL 的列数据类型(col_id 和 col_date)与我的对象相同。

DECLARE
   a      SYS_REFCURSOR;
   var1   OBJ_TBL; 

BEGIN
   TST_OBJ (input_date => '21-Aug-2017', out_cur => a);

  FETCH a bulk collect INTO var1;

  For rec in 1..var1.count
   LOOP     
      DBMS_OUTPUT.put_line (var1(rec).col_id  ||' '|| var1(rec).Col_DATE);
   END LOOP;
END;

/

ORA-06504:PL/SQL:返回结果集变量或查询的类型 不匹配 ORA-06512:在第 8 行

但是,当我这样执行时,它工作正常

DECLARE
   a      SYS_REFCURSOR;
   var1   NUMBER;
   var2   TIMESTAMP (6);
BEGIN
   TST_OBJ (i_date => '21-Aug-2017', out_cur => a);

   LOOP
      FETCH a INTO var1, var2;

      EXIT WHEN a%NOTFOUND;

      DBMS_OUTPUT.put_line (var1 ||' '|| var2);
   END LOOP;
END;

谁能建议这里有什么问题?

【问题讨论】:

【参考方案1】:

您正在使用表集合表达式来取消嵌套表集合:

Open out_cur for select col_id,col_date from table(l_tab);

查询返回两个关系列,而不是单个对象,因此您的光标也有两列。尝试将两个关系列批量收集到匿名块中的单个对象中会引发异常。

我想你可以将它们重新组合为对象:

Open out_cur for select OBJ_TST(col_id,col_date) from table(l_tab);

或者如果您不想明确列出列/字段名称:

Open out_cur for select cast(multiset(select * from table(l_tab)) as obj_tbl) from dual;

但是在您的示例中,表类型有点毫无意义,您可以这样做:

CREATE OR REPLACE PROCEDURE TST_OBJ  (input_date IN     DATE,
                                      out_cur     OUT SYS_REFCURSOR )
AS   
BEGIN

   Open out_cur for
   SELECT OBJ_TST (ti.col_id, ti.col_date)
     FROM MY_TBL ti
    WHERE ti.create_date BETWEEN input_date AND input_date + 1;

END TST_OBJ;
/

但我认为您对函数内部的集合还有其他用途 - 在查询和返回之前对其进行修改。或者,您可以使用 OBJ_TBL 类型的第二个参数而不是 ref 游标,因此调用者不必将其批量收集到自己的本地集合中。

【讨论】:

【参考方案2】:
DECLARE
   a      SYS_REFCURSOR;
   var1   OBJ_TBL; 

BEGIN
   TST_OBJ (input_date => '21-Aug-2017', out_cur => a);

  FETCH a bulk collect INTO var1;

  For rec in 1..var1.count
   LOOP     
      DBMS_OUTPUT.put_line (var1(rec).col_id  ||' '|| var1(rec).Col_DATE);
   END LOOP;
END;
/

游标a 有两列,您正试图将它们批量收集到一个变量中。 Oracle 不会将它们包装在 OBJ_TST 对象中,并且无法匹配它们。

为什么要使用游标:

CREATE OR REPLACE PROCEDURE TST_OBJ  (
  input_date IN  DATE,
  out_objs   OUT OBJ_TBL
)
AS   
BEGIN
   SELECT OBJ_TST( col_id, col_date)
   BULK COLLECT INTO out_objs
   FROM   MY_TBL
   WHERE  create_date BETWEEN input_date AND input_date + 1;
END TST_OBJ;
/

那么你可以这样做:

DECLARE
  var1   OBJ_TBL; 
BEGIN
  TST_OBJ (
    input_date => DATE '2017-08-21',
    out_objs   => var1
  );

  For rec in 1..var1.count LOOP     
    DBMS_OUTPUT.put_line (var1(rec).col_id  ||' '|| var1(rec).Col_DATE);
  END LOOP;
END;
/

【讨论】:

@MTO 我希望使用sys_refcursor 作为OUT 参数。我知道实现我的要求的其他方法,但我一直在寻找我做了什么以及为什么它不起作用。另外,如果您看到我已经发布了显示 `sys_ref 内容的另一种方式,无论如何感谢您的回答。

以上是关于ORA-06504: PL/SQL: 执行时返回结果集变量的类型的主要内容,如果未能解决你的问题,请参考以下文章

关于Oracle游标out参数多层调用的BUG,ORA-06504

如何让 refcursor 结果/输出显示为文本?

PL/SQL 打印出存储过程返回的引用游标

PL/SQL 函数在执行时抛出进程内存错误

执行动态 PL/SQL 块以执行求和并返回值

PL/SQL:将词法参数传递给存储过程