关于 oracle:ORA-06504: PL/SQL: Return types of Result Set variables while execution

ORA-06504: PL/SQL: Return types of Result Set variables while execution

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

ORA-06504: PL/SQL: Return types of Result Set variables or query do
not match ORA-06512: at line 8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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)与我的对象相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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: Return types of Result Set variables or query do
not match ORA-06512: at line 8

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);

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

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

1
OPEN out_cur FOR SELECT OBJ_TST(col_id,col_date) FROM TABLE(l_tab);

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

1
OPEN out_cur FOR SELECT CAST(multiset(SELECT * FROM TABLE(l_tab)) AS obj_tbl) FROM dual;

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

1
2
3
4
5
6
7
8
9
10
11
12
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 游标,因此调用者不必将其批量收集到自己的本地集合中。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 不会将它们package在 OBJ_TST 对象中,并且无法匹配它们。

为什么要使用游标:

1
2
3
4
5
6
7
8
9
10
11
12
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;
/

那么你可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
/