如何使用多个表循环 SYS_REFCURSOR?

Posted

技术标签:

【中文标题】如何使用多个表循环 SYS_REFCURSOR?【英文标题】:How to loop a SYS_REFCURSOR with multiple tables? 【发布时间】:2014-10-09 19:52:46 【问题描述】:

很抱歉问题的标题过于宽泛,但我没有找到进一步简化它的方法。

我正在为客户创建一个包,这个包有一个返回SYS_REFCURSOR 的过程。提供它的查询是一个包含大约 20 个字段的多表选择。在第二个过程中,我需要调用它,并循环遍历结果以提供其他位置。

我在使用循环的into 部分时遇到问题。我不能使用table%ROWTYPE。我试图在程序上声明一个OBJECT,但这是不允许的。我需要FETCH XXX INTO LIST_OF_INDVIDUAL_VARIABLES吗?

DECLARE
    dt_field TABLE1.dt_field%TYPE;
    p_resultset SYS_REFCURSOR;
    p_individual OBJECT ( 
     FIELD0         DATE,
     FIELD1         TABLE.FIELD1%TYPE,
     FIELD2         TABLE.FIELD2%TYPE,
     FIELD3         TABLE.FIELD3%TYPE,
     FIELD4         TABLE.FIELD4%TYPE
 );

 BEGIN
    PACKAGE.PROCEDURE1(dt_field);
    dbms_output.put_line(dt_field);
    PACKAGE.PROCEDURE2(dt_field, p_resultset);

   LOOP 
     -- this do not work
     FETCH p_resultset INTO p_individual;
     EXIT WHEN p_resultset%NOTFOUND;
     -- DO STUFF ON EACH RETURNED ROW
   END LOOP;
   CLOSE p_resultset;      
 END;

【问题讨论】:

“我试图在过程中声明一个 OBJECT 但不允许由于您的企业政策?由于缺乏所需的权限?或者它只是产生某种错误? 看看 Alex Poole 的这个答案也许:***.com/a/11233929/2363712 您需要在 PL/SQL 中声明一个记录类型,而不是一个对象,然后是该记录类型的一个实例。显示你得到的错误会很有帮助。我不确定您是否可以将引用游标提取到记录类型中,即兴发挥。 【参考方案1】:

根据我的评论,不能在 PL/SQL 中创建对象类型,需要声明记录类型,然后声明该类型的实例:

DECLARE
  type r_individual is record (
    FIELD0         DATE,
    FIELD1         TABLE1.FIELD1%TYPE,
    FIELD2         TABLE1.FIELD2%TYPE,
    FIELD3         TABLE1.FIELD3%TYPE,
    FIELD4         TABLE1.FIELD4%TYPE
  );
  p_individual r_individual;
...

您可以将引用游标提取到记录类型中。对象声明上的版本错误,而不是 fetch

根据您的问题,这是一个更完整的示例;我没有你的程序,所以我正在创建一个具有相同类型的虚拟结果集,并为 %TYPE 声明使用了一个虚拟表:

create table table1(dt_field date, field1 number, field2 varchar2(1),
  field3 number, field4 varchar2(1));

set serveroutput on
DECLARE
  type r_individual is record (
    FIELD0         DATE,
    FIELD1         TABLE1.FIELD1%TYPE,
    FIELD2         TABLE1.FIELD2%TYPE,
    FIELD3         TABLE1.FIELD3%TYPE,
    FIELD4         TABLE1.FIELD4%TYPE
  );
  dt_field TABLE1.dt_field%TYPE;
  p_resultset SYS_REFCURSOR;
  p_individual r_individual;

BEGIN
  -- Don't have this package
  -- PACKAGE.PROCEDURE1(dt_field);
  -- dbms_output.put_line(dt_field);
  -- PACKAGE.PROCEDURE2(dt_field, p_resultset);

  -- Dummy result set for demo instead
  OPEN p_resultset FOR q'[select sysdate, 1, 'A', 3, 'C' from dual]'
    || q'[ union all select sysdate, 2, 'B', 4, 'D' from dual]';

  LOOP 
    FETCH p_resultset INTO p_individual;
    EXIT WHEN p_resultset%NOTFOUND;
    -- DO STUFF ON EACH RETURNED ROW
    DBMS_OUTPUT.PUT_LINE(p_individual.field1
      || ':' || p_individual.field2);
  END LOOP;
  CLOSE p_resultset;
END;
/

得到:

anonymous block completed
1:A
2:B

【讨论】:

谢谢伙计,这正是我失败的地方。从 mysql\MariaDB 迁移是一项巨大的努力。仍在努力寻找自己的方式。 出现:INTO 列表中的表达式“P_INDIVIDUAL”类型错误 @delive - 出现在哪里?这段代码在 SQL*Plus 和 SQL Developer 中运行没有错误,同样是 11g 和 12c。什么是完整的 ORA- 或 PLS- 错误消息?还是您的客户端/IDE 自己生成?如果您遇到无法解决的问题,则需要提出一个新问题。 @Alex Poole 错误出现在 FETCH p_resultset INTO p_individual;我有多个表,我收到此错误。例如,您在此代码中有“TABLE1”。我有“表 1”。 “表 2。” “表3。”与行类型 @delive - 那么您还没有调整它以正确匹配您的查询。就像我说的,提出一个新问题,显示您的表格、您的代码版本以及您遇到的问题。

以上是关于如何使用多个表循环 SYS_REFCURSOR?的主要内容,如果未能解决你的问题,请参考以下文章

如何将行附加到现有的 SYS_REFCURSOR?

我试图从 sys_refcursor 获取 bulkcollect 记录并尝试使用 forall 插入另一个表,但它抛出了一条错误消息

如何在有循环和多个级联路径的情况下配置级联删除

SQL 过程可以返回一个表吗?

如何使用来自普通游标的值打开 sys_refcursor?

如何在 oracle 中使用 sys_refcursor 创建动态 sql