user2083834
user2083834

Reputation: 73

Looping through a cursor with a condition on an updated field [PLSQL]

I am currently implementing a PL/SQL procedure, which balances a value in two lists.

Consider this example as background:


I want to loop through all these values one-by-one and settle as much as possible, i.e. that after the first settlement Rec_1 should be 1, Rec_A should be 0. Afterwards, Rec_1 will be settled with Rec_B such that it gets 1, Rec_B gets -2, and so on.

I want to use two cursors to do this, and update the values in its own procedure (or function, if that is necessary), since there is a little more to do than just update this value.

Now, here is my challenge: How do I know which cursor to fetch after a settlement has happened?

Right now, my code for this function looks like this:

PROCEDURE SettleLists (
  ListNegV SYS_REFCURSOR,
  ListPosV SYS_REFCURSOR
) IS
  currentNegV TABLENAME%ROWTYPE;
  currentPosV TABLENAME%ROWTYPE;
BEGIN
  FETCH ListNegV INTO currentNegV;
  FETCH ListPosV INTO currentPosV;
  LOOP
    EXIT WHEN ListNegV%NOTFOUND;
    EXIT WHEN ListPosV%NOTFOUND;
    IF (currentNegV.NUMERICVALUE < 0)
    THEN
      IF (currentPosV.NUMERICVALUE > 0)
      THEN
        Settle(currentPosV, currentNegV);
      ELSE 
        FETCH ListPosV INTO currentPosV;
      END IF;
    ELSE 
      FETCH ListNegV INTO currentNegV;
    END IF;  
  END LOOP;
END;

Inside the settle procedure, there will be an UPDATE on both records. Since the variables and cursor values are not updated, this will produce an infinite loop. I could update the parameter of settle when the record is updated in the database as well, but since I am not used to cursors, you might have a better idea.

I could consider the cursor to be strongly typed, if that makes any difference. If there is a better way than using a cursor, feel free to suggest it.

Finally, I was playing around with SELECT FOR UPDATE and UPDATE WHERE CURRENT OF, but it did not seem to work when passing the cursor to a procedure in between. If anyone has some idea on this, I would also appreciate your help.

Upvotes: 0

Views: 1240

Answers (1)

Jignesh
Jignesh

Reputation: 88

Here is a what I would do. I will surely add some comments.

This is running fine in Oracle 11Gr2 and I am hoping it will run fine even in 7i :).

declare
    cursor c1 is 
        select 'REC_1' HEader,2 Val from dual
        union 
        select 'REC_2' HEader,1 Val from dual
        union 
        select 'REC_3' HEader,2 Val from dual;
    cursor c2 is
        select 'REC_A' HEader,-1 Val from dual
        union 
        select 'REC_B' HEader,-3 Val from dual
        union 
        select 'REC_C' HEader,-2 Val from dual;
    num_bal1 number;
    num_bal2 number;
    num_settle_amt number;
    rec_type_c1 c1%rowtype;
    rec_type_c2 c2%rowtype;
begin

    Open c1;
    open c2;
    fetch c1 into rec_type_c1;
    fetch c2 into rec_type_c2;
    num_bal1 := nvl(rec_type_c1.val,0);
    num_bal2 := rec_type_c2.val;
    Loop

        exit when c1%notfound or c2%notfound;
        Loop
            dbms_output.put_line('Processing ' || rec_type_c1.header || ' with ' || num_bal1);
            --In your example there are only +ve for 1 and -ve for 2. But if that is not correct, check for signs and next 3 statements
            num_settle_amt := least(abs(num_bal1), abs(num_bal2) );
            num_bal1 := num_bal1 - num_settle_amt;
            num_bal2 := num_bal2 + num_settle_amt;
            dbms_output.put_line('Setteled ' || num_settle_amt || ' of ' || rec_type_c1.header  || ' with ' || rec_type_c2.header );
            if num_bal1 = 0 then
                --Update in the table. It will not impact variable.
                fetch c1 into rec_type_c1;
                num_bal1 := nvl(rec_type_c1.val,0);
            end if;

            if num_bal2 = 0 then
                --Update in the table. It will not impact variable.
                fetch c2 into rec_type_c2;
                num_bal2 := nvl(rec_type_c2.val,0);
            end if;

        End loop;
    end loop;
    close c1;
    close c2;
end;

Upvotes: 1

Related Questions