Oracle. Reuse cursor as parameter in two procedures

故事扮演 提交于 2019-12-24 12:09:21

问题


Let's create two test procedures:

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

Then let's try to open cursor and pass it to these procedures in order:

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;

As you can see, I can't use already fetched cursor in second procedure, because ORACLE cursors are forward-and-read-only. What ways can help to solve this task?

I can't simply bring these procedures into one. Need to keep their logic separate from each other.


回答1:


You need to open the cursor twice. Using a string variable to hold the query will prevent you from writing the query twice.

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



回答2:


Cursors are NOT designed to be re-used: you read them once, keep moving forward and as you're doing so you're discarding any previously scanned rows. Think of a Java stream... This is a feature, not a bug - cursors are intended to be very much memory/disk efficient.

So the options are: 1) As Nicolas mentioned, close and re-open the same cursor. You'll pay the performance penalty of running the same query twice 2) Store the query results in a temp table (good for very large sets as it would use disk) 3) Store the query results in a collection (nested table - good for small-medium sized tables) 4) If you really can't do any of the easy solutions above you can try to mess around with your code so that you have one "dispatch" procedure that reads the cursor and then passes each row to your 2 "worker" procedures. You'd have to modify your stored procs to be able to process row at a time



来源:https://stackoverflow.com/questions/17919771/oracle-reuse-cursor-as-parameter-in-two-procedures

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!