Reputation: 73
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
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