Oracle 神谕在两个过程中重用游标作为参数

Oracle 神谕在两个过程中重用游标作为参数,oracle,plsql,oracle11g,cursor,Oracle,Plsql,Oracle11g,Cursor,让我们创建两个测试程序: CREATE OR REPLACE PROCEDURE Aaaa_Test1( pDog SYS_REFCURSOR ) IS TYPE tDogRec is record (objid varchar2(7), lim number, debt number); TYPE tDog IS TABLE OF tDogRec; vDog tDog; BEGIN IF pDog%ISOPEN THEN FETCH pDog BULK COLLEC

让我们创建两个测试程序:

CREATE OR REPLACE PROCEDURE Aaaa_Test1(
  pDog SYS_REFCURSOR
) IS
  TYPE tDogRec is record (objid varchar2(7), lim number, debt number);
  TYPE tDog IS TABLE OF tDogRec;
  vDog tDog;
BEGIN
  IF pDog%ISOPEN THEN
    FETCH pDog BULK COLLECT INTO vDog;

    IF vDog.count >= 1 THEN
      FOR i IN vDog.First..vDog.Last LOOP
        Dbms_Output.Put_Line('Aaaa_Test1 = '||vDog(i).Objid);
      END LOOP;
    END IF;

  END IF;
END; -- Aaaa_Test1 Procedure
/
CREATE OR REPLACE PROCEDURE Aaaa_Test2(
  pDog SYS_REFCURSOR
) IS
  TYPE tDogRec is record (objid varchar2(7), lim number, debt number);
  TYPE tDog IS TABLE OF tDogRec;
  vDog tDog;
BEGIN
  IF pDog%ISOPEN THEN
    FETCH pDog BULK COLLECT INTO vDog;

    IF vDog.count >= 1 THEN
      FOR i IN vDog.First..vDog.Last LOOP
        Dbms_Output.Put_Line('Aaaa_Test2 = '||vDog(i).Objid);
      END LOOP;
    END IF;

  END IF;
END; -- Aaaa_Test2 Procedure
然后,让我们尝试打开游标并按顺序将其传递给这些过程:

DECLARE
  Vcdogcur SYS_REFCURSOR;    
BEGIN
  OPEN Vcdogcur FOR
    select '6518535' objid, 10000 lim,0 debt
      from dual
     union all
    select '6518536', 0,500
      from dual
     union all
    select '5656058', 0,899
      from dual
     union all
    select '2180965', 5000,0
      from dual
     union all
    select '2462902', 0,100
      from dual;

  Aaaa_Test1(Vcdogcur);
  Aaaa_Test2(Vcdogcur);
  CLOSE Vcdogcur;
END;
正如您所看到的,我不能在第二个过程中使用已经获取的游标,因为ORACLE游标是向前的,并且是只读的。有什么方法可以帮助解决这项任务


我不能简单地把这些程序合并在一起。需要将它们的逻辑彼此分开。

您需要打开光标两次。使用字符串变量保存查询将防止您写入查询两次

DECLARE
      Vcdogcur SYS_REFCURSOR;    
      dyn_query varchar2(500);
BEGIN      
    dyn_query  := 'select ''6518535'' objid, 10000 lim,0 debt
      from dual
     union all
    select ''6518536'', 0,500
      from dual
     union all
    select ''5656058'', 0,899
      from dual
     union all
    select ''2180965'', 5000,0
      from dual
     union all
    select ''2462902'', 0,100
      from dual' ;


  open Vcdogcur for dyn_query ;
  Aaaa_Test1(Vcdogcur);
  CLOSE Vcdogcur;
  open Vcdogcur for dyn_query ;
  Aaaa_Test2(Vcdogcur);
  close Vcdogcur;
END;
/

您需要打开光标两次。使用字符串变量保存查询将防止您写入查询两次

DECLARE
      Vcdogcur SYS_REFCURSOR;    
      dyn_query varchar2(500);
BEGIN      
    dyn_query  := 'select ''6518535'' objid, 10000 lim,0 debt
      from dual
     union all
    select ''6518536'', 0,500
      from dual
     union all
    select ''5656058'', 0,899
      from dual
     union all
    select ''2180965'', 5000,0
      from dual
     union all
    select ''2462902'', 0,100
      from dual' ;


  open Vcdogcur for dyn_query ;
  Aaaa_Test1(Vcdogcur);
  CLOSE Vcdogcur;
  open Vcdogcur for dyn_query ;
  Aaaa_Test2(Vcdogcur);
  close Vcdogcur;
END;
/

游标不是为重复使用而设计的:您读取它们一次,然后继续前进,这样做的同时,您将丢弃以前扫描的任何行。想想Java流。。。这是一个功能,而不是一个bug-游标的目的是非常高效的内存/磁盘

因此,选择是: 1) 正如Nicolas提到的,关闭并重新打开同一个光标。运行同一个查询两次将导致性能损失 2) 将查询结果存储在临时表中(适用于非常大的集合,因为它将使用磁盘) 3) 将查询结果存储在集合中(嵌套表-适用于中小型表)
4) 如果您真的不能执行上述任何简单的解决方案,您可以尝试将代码弄乱,这样您就有一个“分派”过程来读取光标,然后将每一行传递给两个“工作”过程。您必须修改存储的进程,以便能够一次处理行

游标不是为重复使用而设计的:您读取它们一次,然后继续前进,在这样做的过程中,您将丢弃以前扫描的任何行。想想Java流。。。这是一个功能,而不是一个bug-游标的目的是非常高效的内存/磁盘

因此,选择是: 1) 正如Nicolas提到的,关闭并重新打开同一个光标。运行同一个查询两次将导致性能损失 2) 将查询结果存储在临时表中(适用于非常大的集合,因为它将使用磁盘) 3) 将查询结果存储在集合中(嵌套表-适用于中小型表)
4) 如果您真的不能执行上述任何简单的解决方案,您可以尝试将代码弄乱,这样您就有一个“分派”过程来读取光标,然后将每一行传递给两个“工作”过程。您必须修改存储过程才能一次处理行

为什么要/需要这样做?@FrankSchmitt,因为真正的查询非常大,我不想在这些过程中单独重复它。也许我需要考虑临时表。如果基本查询是相同的,为什么不在一个过程中实现逻辑呢?它会消除复杂性?@ HHSHIT,因为我们为完全不同的分配过程使用单独的逻辑。@ Okloks,那么您可以将查询作为字符串传递给过程,然后打开游标。它在程序本身中。你为什么想要/需要这样做?@FrankSchmitt,因为真正的查询非常大,我不想在这些程序中单独重复它。也许我需要考虑临时表。如果基本查询是相同的,为什么不在一个过程中实现逻辑呢?它会消除复杂性?@ HHSHIT,因为我们为完全不同的分配过程使用单独的逻辑。@ Okloks,那么您可以将查询作为字符串传递给过程,然后打开游标。这一点很好,但从编程角度来说,如果我编写两个单独的查询,这几乎是相同的解决方案。确切地说,一个游标不能读取两次。现在,您还可以读取游标一次,将数据存储在集合(表)中,然后使用两次。这一点很好,但从编程角度讲,如果我编写两个单独的查询,这几乎是相同的解决方案。确切地说,您不能读取游标两次。现在,您还可以读取光标一次,将数据存储在集合(表)中,然后使用该集合两次。