How do you fetch a cursor variable multiple times - oracle

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;

Related

handling excpetions in plsql block while running in a loop

I have a requirement where I need to drop partitions for more than one tables in a loop.If for some reason that partition doesnt exist in a table the whole procedure is giving error . But I want to drop other partititions which exists in other tables without coming out of the loop
Use an inner begin-exception-end block ("inner" meaning "within a loop"). Something like this:
begin
for cur_r in (select whatever from ...) loop
-- inner block begins here
begin
do stuff here
exception
when ... then ...
end;
-- inner block ends here
end loop;
end;

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

PL/SQL - Pre actions if cursor is found

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;

Oracle 11g PL/SQL cursor,intersect query

I have the following query
select distinct name from table1
intersect
select distinct name from table2;
I load the resultset into a cursor in a PL/SQL procedure, like so:
cursor c1 is (select distinct name from table1
intersect
select distinct name from table2);
For some reason the last value in the resultset is duplicated in the cursor. This does not happen when running the query by itself. Any ideas why this is happening?
Code for the loop:
var table.col%type;
BEGIN
OPEN c1;
LOOP
BEGIN
exit when c1%NOTFOUND;
FETCH c1 into var;
INSERT INTO table values (col1, var);
commit;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
CONTINUE;
END;
END LOOP;
END;
EXIT WHEN .. clause should come after FETCH.
Let's say, your cursor had 10 records to return. Before the first fetch is fired, %NOTFOUND evaluated to NULL, and the processing moves to the next statement, which is FETCH in your case. Now, if we fast forward to the 10th iteration, FETCH will get the 10th record, and the same is inserted into your destination table. The loop will move ahead, and since your EXIT WHEN %NOTFOUND is before fetch, it still has the value from last iteration, and it lets the control move ahead, and there, fetch will not be able to get any record, but the code will anyhow insert the last row it retrieved in 10th iteration. Now in the next loop, c1%NOTFOUND will be evaluated to TRUE and the loop will terminate
var table.col%type;
BEGIN
OPEN c1;
LOOP
BEGIN
FETCH c1 into var;
exit when c1%NOTFOUND;
INSERT INTO table values (col1, var);
commit;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
CONTINUE;
END;
END LOOP;
END;
This is typical of the problems you see with explicit cursors.
Your first choice should be a single SQL statement, nothing more.
If you had to use a cursor, you should be using an implicit one wherever possible.

PL/SQL cursor in the while

This is what I am trying to achieve:
define a cursor
which return me list of rows
use the rows to do some modify tables
repeat 2 and 3 until cursor returns no result.
this is what I have done so far
DECLARE
CURSOR c1 IS
[My SQL HERE];
BEGIN
FOR r1 in c1 LOOP
[modify tables]
END;
question is where do I put the while? I would do it before the for loop. but whats the syntax in pl/sql to describe c1 has result?
Note after c1 fullly finish I need to rerun the cursor code. Make another iteration . Because the result will be different. That's why I needed the while
The answer is combine 'while' with 'for '. Obviously only if you want to run the cursor multiple times, because you are update/alter something inside the cursor, and the condition changed, thus you need to re-run the cursor again.
here is the basic structure:
DECLARE
CURSOR c1 IS
[My SQL HERE];
BEGIN
WHILE CONDITION LOOP
FOR r1 in c1 LOOP
[modify tables]
END LOOP; -- for loop
[Check The Condition]
END LOOP; -- while loop
END;
e.g
DECLARE
counts NUMBER := -1;
CURSOR c1 IS
[Statement Here];
BEGIN
WHILE count != 0 LOOP
FOR r1 in c1 LOOP
[modify tables]
END LOOP; -- for loop
SELECT count(*) ...... INTO counts
END LOOP; -- while loop
END;
First of all I would recommend to think about conventional update without cursors because the best part of them is slower. I also don't understand what for you would like to replace FOR by WHILE. They work nearly similar. At any case the best source of advice is the documentation from Oracle http://docs.oracle.com/cd/B14117_01/appdev.101/b10807/13_elems020.htm
You don't need a separate WHILE. The FOR ... LOOP will iterate over the rows returned by the cursor:
FOR r1 IN c1 LOOP
-- r1 is the current row from the cursor
END LOOP;
There are two ways to handle a cursor, so perhaps that's caused confusion; the alternative is something like:
OPEN c1;
LOOP
FETCH c1 INTO r1; -- where r1 is declared
EXIT WHEN c1%NOTFOUND;
-- do something with r1
END LOOP;
CLOSE c1;
Personally I usually find the FOR ... LOOP syntax simpler.

Resources