【问题标题】:Oracle. Reuse cursor as parameter in two procedures甲骨文。在两个过程中重用游标作为参数
【发布时间】:2013-07-28 23:47:20
【问题描述】:

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

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 游标是向前和只读的。有什么方法可以帮助解决这个任务?

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

【问题讨论】:

  • 您为什么想要/需要这样做?
  • @FrankSchmitt 因为真正的查询非常大,我不想在这些过程中单独重复它。也许我需要考虑临时表..
  • 如果基本查询相同,为什么不在一个程序中实现逻辑,它会消除肤色?
  • @Harshit 因为我们对具有完全不同分配的过程使用单独的逻辑。
  • @Okloks 那么您可能可以将查询作为字符串传递给程序,然后在程序本身中为它打开游标。

标签: oracle plsql oracle11g cursor


【解决方案1】:

游标不是为重复使用而设计的:您只需阅读一次,然后继续前进,在这样做的同时,您将丢弃任何以前扫描过的行。想想 Java 流...这是一个特性,而不是错误 - 游标旨在提高内存/磁盘效率。

所以选项是: 1)正如尼古拉斯所说,关闭并重新打开同一个光标。您将支付两次运行相同查询的性能损失 2)将查询结果存储在临时表中(适用于非常大的集合,因为它会使用磁盘) 3)将查询结果存储在一个集合中(嵌套表——适合中小型表) 4)如果您真的无法执行上述任何简单的解决方案,您可以尝试弄乱您的代码,以便您拥有一个读取光标的“调度”程序,然后将每一行传递给您的 2 个“工人”程序。您必须修改存储过程才能一次处理行

【讨论】:

    【解决方案2】:

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

    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;
    /
    

    【讨论】:

    • 好点,但在编程上,如果我编写两个单独的查询,这几乎是相同的解决方案。
    • 没错,你不能读取光标两次。现在您还可以读取一次光标,将数据存储在一个集合(TABLE OF)中,然后使用它两次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-06
    • 2011-05-13
    • 1970-01-01
    相关资源
    最近更新 更多