SELECT records only once within a stored procedure and operate on selected records

50 Views Asked by At

I am selecting same set of records twice, once to return IN REF_CURSOR and then selecting same records to build a CSV so that i can update all records in IN clause .... Can i some how change my procedure to SELECT only once instead of selecting same records twice

      PROCEDURE LOADBATCH(
      inBUCKET_SIZE IN NUMBER,
      OUTCURSOR OUT REF_CURSOR )
  AS
    V_HANDLE      VARCHAR2(2000);
    V_LOCK_RESULT INTEGER;
    IDs           VARCHAR2(2000);
  BEGIN
    BEGIN
      V_HANDLE      := GET_LOCK_HANDLE('BATCH');              
      V_LOCK_RESULT := DBMS_LOCK.REQUEST(V_HANDLE, TIMEOUT => 1); 
      DBMS_OUTPUT.PUT_LINE(V_LOCK_RESULT);
      IF V_LOCK_RESULT <> 1 THEN
        OPEN OUTCURSOR FOR SELECT BATCH_ID,INSTRUCTION_ID,INSTRUCTION_DUMP,BATCH_MSG_TYPE,BATCH_AMOUNT,BATCH_CURRENCY,RECIEVED_DATETIME,MODIFIED_DATETIME,SETTLEMENT_DATE,BATCH_STATUS,FROM_MMBID,BATCH_DATE,MODIFICATION_DATETIME,PARENTBATCH_ID,INSTR_REASON FROM
        ( SELECT DISTINCT BI.*,
          BM.*,
          BM.AMOUNT          AS BATCH_AMOUNT,
          BM.CURRENCY        AS BATCH_CURRENCY,
          BI.PARENT_BATCH_ID AS PARENTBATCH_ID,
          BI.REASON          AS INSTR_REASON
        FROM ACT.BATCH_INSTRUCTIONS BI
        INNER JOIN ACT.BATCH_MESSAGES BM
        ON BI.BATCH_ID  =BM.ID
        WHERE (BI.STAGE = 'NEW'
        OR (BI.STAGE    = 'PICKED'
        AND (SYSDATE    > (BI.LAST_PICKED_AT + interval '65' second))))
        AND (BM.STAGE  <> 'COMPLETED')
        ORDER BY LAST_PICKED_AT ASC
        ) WHERE ROWNUM <=inBUCKET_SIZE ;
        
        SELECT listagg(INSTRUCTION_ID, ',') WITHIN GROUP (
        ORDER BY INSTRUCTION_ID) AS concatenation
        INTO IDs
        FROM
          (SELECT DISTINCT *
          FROM ACT.BATCH_INSTRUCTIONS BI
          INNER JOIN ACT.BATCH_MESSAGES BM
          ON BI.BATCH_ID  =BM.ID
          WHERE (BI.STAGE = 'NEW'
          OR (BI.STAGE    = 'PICKED'
          AND (SYSDATE    > (BI.LAST_PICKED_AT + interval '65' second)))
          )
          AND (BM.STAGE  <> 'COMPLETED')
          ORDER BY LAST_PICKED_AT ASC
          )
        WHERE ROWNUM <=inBUCKET_SIZE ;
        DBMS_OUTPUT.PUT_LINE('IDs are:');
        DBMS_OUTPUT.PUT_LINE(IDs);
        IF( IDs IS NOT NULL) THEN
          UPDATE ACT.BATCH_INSTRUCTIONS
          SET LAST_PICKED_AT    =sysdate,
            STAGE               = 'PICKED'
          WHERE INSTRUCTION_ID IN
            (SELECT INSTRUCTION_ID
            FROM ACT.BATCH_INSTRUCTIONS
            WHERE INSTRUCTION_ID IN
              (SELECT regexp_substr(IDs,'[^,]+', 1, level)
              FROM dual
                CONNECT BY regexp_substr(IDs, '[^,]+', 1, LEVEL) IS NOT NULL
              )
            );
          COMMIT;
        END IF;
      END IF;
    EXCEPTION
    WHEN NO_DATA_FOUND THEN
      NULL;
    END;
    --                        DBMS_OUTPUT.PUT_LINE('releasing lock:');
    V_LOCK_RESULT := DBMS_LOCK.RELEASE(V_HANDLE);
  END LOADBATCH;
1

There are 1 best solutions below

1
On

Wont work with one select because "select into" does not accept dynamic SQL nor cursors.