PL/SQL - Pre actions if cursor is found - oracle

I have a simple cursor like this:
CURSOR emp_cur
IS
SELECT *
FROM employee
WHERE age > 20;
In my procedure, I want to do some pre-actions only if there are employee in cursor. After that pre-action, I process all rows.
I need this because only if exists employee in that cursor i need to cleanup some tables, otherwise i should "RETURN".
so the code could be:
OPEN emp_cur;
/* Here i need to do pre-action only if emp_cur has rows*/
IF /* has rows*/
THEN
/* do some actions*/
END IF;
LOOP
FETCH emp_cur INTO emp_rec;
EXIT WHEN emp_cur%NOTFOUND;
END LOOP;
CLOSE emp_cur;
For now, i have a "dirty" solution where i open cursor:
First to check if there are rows
Do pre-action and close
Open/fetch again to process rows, and close again

First to check if there are rows
You cannot know about the rows until you FETCH.
From documentation link ,
After a cursor or cursor variable is opened but before the first
fetch, %FOUND returns NULL. After any fetches, it returns TRUE if the
last fetch returned a row, or FALSE if the last fetch did not return a
row.
Once you have fetched the rows, then before processing the rows, you could use %FOUND.
For example,
OPEN c1;
LOOP
FETCH c1 INTO my_ename, my_salary;
IF c1%FOUND THEN -- fetch succeeded
-- Do something
ELSE -- fetch failed, so exit loop
EXIT;
END IF;
END LOOP;

Thinking a little i've wrote this procedure that avoid an IF inside the loop. I know, is a little "strange" but is the only thing i've think works:
OPEN emp_cur;
FECTH emp_cur INTO emp_rec;
IF emp_cur%FOUND
THEN
-- pre actions
END IF;
LOOP
EXIT WHEN emp_cur%NOTFOUND;
-- do something in the loop
FECTH emp_cur INTO emp_rec; -- First fetch was done before the if
END LOOP;
CLOSE emp_cur;

Related

I want to call this procedure and pass the variables that are fetched in the cursor

I want to pass these variables but getting error
my code:
begin
open CUR_SCENARIO_1;
fetch CUR_SCENARIO_1 bulk collect
into v_id, v_state, v_toc, v_sub, v_resp, v_pp_status limit 10;
FOR x in v_id.count()
SP_Create_original_record(v_id, v_state, v_toc, v_sub, v_resp, v_pps);
END LOOP;
end;
you need a Loop keyword and a The starting and the ending value of the Loop.
FOR x in 1 .. v_id.count() loop
SP_Create_original_record(v_id, v_state, v_toc, v_sub, v_resp, v_pps);
END LOOP;
You also need to go a step further; nest the FOR loop in a "fetch loop". Without doing so you will process the first 10 rows from you cursor and the exit. If the cursor returns more, the additional will not be processed.
loop -- fetch loop
fetch CUR_SCENARIO_1 bulk collect into v_id, ... limit 10;
for x in 1..v_id.count()
loop
...
end loop ;
exit when v_id.count() < 10;
end loop; -- fetch loop

How to execute Stored Procedure inside Stored Procedure with Cursor in Oracle

I am new in Oracle,
In SQL Server I can easily execute a stored procedure inside storedprocedure
even using a cursor.
now I can't figure it out in Oracle here is my code below.
CREATE OR REPLACE PROCEDURE ZSP_INSMASTERDATASTM
AS
l_total INTEGER := 10000;
CURSOR c1
IS
SELECT DISTINCT PRODFROMTO FROM DJ_P9945LINKS;
l_PRODFROMTO c1%ROWTYPE;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO l_PRODFROMTO;
EXIT WHEN c1%NOTFOUND;
EXECUTE ZSP_GETMASTERDATASTM (l_PRODFROMTO);
EXIT WHEN l_total <= 0;
END LOOP;
CLOSE c1;
END ZSP_INSMASTERDATASTM;
i got error on execute ZSP_GETMASTERDATASTM (l_PRODFROMTO);
Just remove EXECUTE. However, note that your loop will NEVER exit because L_TOTAL is never going to be less than zero - you should fix that.
Otherwise, consider using cursor FOR loop as it is simpler to maintain - you don't have to declare a cursor variable, open cursor, fetch, take care about exiting the loop, close the cursor. Have a look at this example:
CREATE OR REPLACE PROCEDURE zsp_insmasterdatastm
AS
BEGIN
FOR cur_r IN (SELECT DISTINCT prodfromto FROM dj_p9945links)
LOOP
zsp_getmasterdatastm (cur_r.prodfromto);
END LOOP;
END;
Quite simpler, isn't it?

PL/SQL -If exists in Table type of varchar2 not working

I am using a huge table which loops inside a cursor so i thought rather than querying on each iteration, put the particular data in a Table type and then check data exists inside the loop.
declare
type type_product_list is table of varchar(6);
product_list type_product_list;
begin
SELECT distinct(PRODUCT_NUMBER)
BULK COLLECT INTO product_list
FROM WEB_PRODUCTS web WHERE some conditions;
FOR i IN 1..product_list.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(product_list(i)); -- This line printing properly.
END LOOP;
IF product_list.EXISTS('00029') THEN -- This condition always fails
DBMS_OUTPUT.PUT_LINE('Found');
ELSE
DBMS_OUTPUT.PUT_LINE('Not Found');
END IF;
end;
Output
00029
00030
00031
00032
..... other data
NOT FOUND
Please help, how can I get the IF block executed.
*Update
Main purpose of this problem is to call a function inside the IF block, and if block itself will be inside a cursor loop which gives dynamic product id in each iteration, i.e. if the product id exists then call that function.
begin
SELECT distinct(PRODUCT_NUMBER)
BULK COLLECT INTO product_list
FROM WEB_PRODUCTS web WHERE some conditions;
OPEN cur_cms_scriptdtl();
LOOP
FETCH cur_cms_scriptdtl INTO productId, productName;
EXIT WHEN cur_cms_scriptdtl%notfound;
IF product_list.EXISTS(productId) THEN
-- Function call
END IF;
END LOOP;
CLOSE cur_cms_scriptdtl;
After some digging and help from Oracle docs, I was able to get it without FOR LOOP.
The helping angel here is : member of
BEGIN
SELECT distinct(PRODUCT_NUMBER)
BULK COLLECT INTO product_list
FROM WEB_PRODUCTS web WHERE some conditions;
OPEN cur_cms_scriptdtl();
LOOP
FETCH cur_cms_scriptdtl INTO productId, productName;
EXIT WHEN cur_cms_scriptdtl%notfound;
IF productId member of product_list THEN
-- Function call
END IF;
END LOOP;
CLOSE cur_cms_scriptdtl;
In collections, exists method receives as parameter an index, not a value.
IF product_list(i) = '00029' THEN
Try this:
DECLARE
type type_product_list is table of varchar(6);
product_list type_product_list;
vFound BOOLEAN := false;
BEGIN
FOR i IN 1..product_list.COUNT LOOP
dbms_output.put_line(product_list(i));
IF product_list(i) = '00029' THEN
vFound := true;
exit;
END IF;
END LOOP;
IF vFound THEN
dbms_output.put_line('Found');
ELSE
dbms_output.put_line('Not Found');
END IF;
END LOOP;

Cursor of Oracle with Duplicate of final Record

Why am getting duplicate records ? pls correct me.Thanks in Advance.
declare
clazzes_rec clazzes%rowtype;
cursor clazzes_cur is select * from clazzes;
begin
if clazzes_cur%isopen then
dbms_output.put_line('Cursor is not open,trying to Open.... ... .. .');
end if;
open clazzes_cur;
dbms_output.put_line('Cursor opened :');
loop
fetch clazzes_cur into clazzes_rec;
dbms_output.put_line('id:'||clazzes_rec.id||':name:'||clazzes_rec.name);
exit when clazzes_cur%notfound;
end loop;
close clazzes_cur;
end;
Ouput :
Cursor opened :
id:1:name:leo1
id:2:name:leo2
id:3:name:leo3
id:4:name:leo4
id:4:name:leo4
PL/SQL procedure successfully completed
Just swap the lines:
loop
fetch clazzes_cur into clazzes_rec;
exit when clazzes_cur%notfound;
dbms_output.put_line('id:'||clazzes_rec.id||':name:'||clazzes_rec.name);
end loop;
When you have fetched the last record and trying to fetch the next clazzes_cur%notfound becomes true but before it has a chance to exit from loop you are outputting the last record once again.

How do you fetch a cursor variable multiple times

I am passing a cursor as input parameter in a function.
Function (p_cur IN curType) ...
Loop (outer loop)
Loop (inner loop)
fetch p_cur into p_cur_rec;
exit when p_cur%notfound;
do some processing here...
end loop;
END Loop;
The inner loop fetches all the cursor records and i was able to go through each iteration to process the data.
However, when the outer loop fetches the 2nd record, the inner loop doesn't seem to fetch from the cursor again. It appears the cursor record is already fetched and can't be used again.
My question is how do you overcome this issue so that the cursor can be fetched again?
You can use the cursor to do your inner loop like this :
cursor c_1 as
select ...
from ..
where ...
rec c_1%rowtype;
begin
for rec in c_1 loop
...
end loop;
end;

Resources