Oracle REF Cursors - oracle

Is there a way to perform any processing after a ref cursor is opened for an application to read from?
So, I have a ref cursor: OPEN p_data FOR v_select. The application reads from that. Afterwards, can my procedure continue processing? Or is it done?
Please advise

Once the cursor is open, you can FETCH from it until you reach until no more data is retrieved. At that point or sooner if you're done processing the data sooner you can CLOSE the cursor.
declare
p_data sys_refcursor;
v_select varchar2(1000) := 'select * from dual';
type data_rec is record (dummy dual.dummy%type);
type data_tab is table of data_rec;
l_data data_tab;
begin
OPEN p_data FOR v_select;
LOOP
FETCH p_data BULK COLLECT INTO l_data LIMIT 100;
FOR r in 1 .. l_data.count LOOP
dbms_output.put_line(l_data(r).dummy);
END LOOP;
EXIT WHEN p_data%notfound;
END LOOP;
CLOSE p_data;
end;

Related

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?

How to build a dynamic PLSQL query to fetch records?

I am trying to create a stored procedure in Oracle and make a dynamic query work to get a bunch of records. I have read many examples but so far I can't get this to work unless I do this:
CREATE OR REPLACE PROCEDURE GiveMeResultSet(
v_par1 IN CHAR,
v_par2 IN CHAR,
v_par3 IN CHAR,
v_par4 IN VARCHAR2,
v_par5 IN VARCHAR2,
v_par6 IN VARCHAR2,
cur_typ OUT SYS_REFCURSOR)
IS
BEGIN
OPEN cur_typ FOR 'select * from complex_query';
--CLOSE cur_typ;
END;
And I am executing it this way:
var c refcursor;
execute GiveMeResultSet(null,null,null,null,null,null,:c);
print c;
This way I get the header names and the records from the query, but I am not closing the cursor that is fetching the results. If I close it then I get nothing at all. I guess leaving it open could cause some kind of memory leak problem at some point.
I have seen similar cases in Oracle documentation where they do something like this:
sql_stmt := 'SELECT * FROM emp';
OPEN emp_cv FOR sql_stmt;
LOOP
FETCH emp_cv INTO emp_rec;
EXIT WHEN emp_cv%NOTFOUND;
-- process record
END LOOP;
CLOSE emp_cv;
But I have no clue what goes on the "process record" part of the code which would allow to get the whole set of records at the end, plus that my record has a complex structure that doesn't fit with a fixed set of fields as in a table.
Can you please show me the proper way to do this?.
Thanks a lot.
ok CodeRoller, here is my sample code for a unspecified ref cursor:
Code of the Function which returns the ref cursor:
create or replace function test_ref_cursor(pi_sql_statement in varchar2) return SYS_REFCURSOR is
result_cursor SYS_REFCURSOR;
begin
open result_cursor for pi_sql_statement;
return result_cursor;
end;
Now, in the next step I use this function to get data from v$parameter:
declare
type t_my_cursor is ref cursor;
my_cursor t_my_cursor;
l_rec v$parameter%rowtype;
begin
my_cursor := test_ref_cursor('select * from v$parameter');
loop
fetch my_cursor into l_rec;
exit when my_cursor%notfound;
dbms_output.put_line(l_rec.name || ' = ' || l_rec.value);
end loop;
close my_cursor;
end;
Take care, to close the ref-cursor!

PLS-00221: 'C1'(cursor) is not a procedure or is undefined

I am creating a package to use with Jasper reports where I learnt that I need SYS_REFCURSOR but I cannot seem to be able to Loop my cursors:eg
create or replace PACKAGE BODY fin_statement_spool
AS
PROCEDURE fin_main_spool(vacid in VARCHAR2, vfromdate in date, vtodate in date,c1 out SYS_REFCURSOR,c2 out SYS_REFCURSOR)
AS
cramount NUMBER;
dramount NUMBER;
countcr NUMBER;
countdr NUMBER;
BEGIN
OPEN c1 FOR
SELECT
.......;
OPEN c2 FOR
SELECT ........;
BEGIN
FOR i IN c1--Error is here
LOOP
rnum := 0;
cramount := 0;
dramount := 0;
countdr := 0;
countcr := 0;
..........
Isn't this the right way?
You appear to have confused explicit cursors, e.g.:
declare
cursor cur is
select dummy from dual;
begin
for rec in cur
loop
dbms_output.put_line(rec.dummy);
end loop;
end;
/
with a ref cursor - which is a pointer to an open cursor.
You would typically use a ref cursor to open a cursor in the db and pass it back to the calling app for it to loop through.
The way you have declared the ref cursors as out parameters and then tried to loop through them in the same procedure does not make sense - once you have fetched a record from a cursor, you cannot re-fetch it.
If you absolutely must loop through a ref cursor, you'd use this sort of syntax:
declare
cur sys_refcursor;
rec dual%rowtype;
begin
open cur for select dummy from dual;
loop
fetch cur into rec;
exit when cur%notfound;
dbms_output.put_line(rec.dummy);
end loop;
end;
/
but as I said, in general, you wouldn't be looping through ref cursors in the db, you'd be doing that in the calling code.
Perhaps if you updated your question with the requirements you're trying to fulfil, we could suggest a better way of doing it.

expression of wrong type oracle error

I am trying to execute the below plsql program, but facing expression of wrong type. Could anyone let me know what might be the error?
CREATE OR REPLACE PROCEDURE CLN_TBL (CTRLM IN VARCHAR2, CTG IN VARCHAR,SBCT IN NUMBER, RTDT IN NUMBER )
AS
V_SQL VARCHAR(2000);
V_TABLE VARCHAR(30);
CURSOR TBL_CUR
IS
SELECT TGT_TABLE_NAME FROM ODS_USER.CLNP WHERE CONTROLM=CTRLM AND APPL_CTGY=CTG AND APPL_SUB_CTGY= SBCT;
L_TGT_TABLE_NAME TBL_CUR%ROWTYPE;
BEGIN
OPEN TBL_CUR;
LOOP
FETCH TBL_CUR INTO L_TGT_TABLE_NAME;
V_TABLE:= L_TGT_TABLE_NAME ;
EXIT WHEN TBL_CUR%NOTFOUND;
V_SQL:='DELETE FROM '||V_TABLE||' WHERE RPT_DT_ID'||'=:1';
EXECUTE IMMEDIATE V_SQL using RTDT;
END LOOP;
COMMIT;
CLOSE TBL_CUR;
END;
As Exhausted said you cant assign row variable to varchar so You should take TGT_TABLE_NAME from row variable, like below should work;
CREATE OR REPLACE PROCEDURE CLN_TBL (CTRLM IN VARCHAR2, CTG IN VARCHAR,SBCT IN NUMBER, RTDT IN NUMBER )
AS
V_SQL VARCHAR(2000);
V_TABLE VARCHAR(30);
CURSOR TBL_CUR
IS
SELECT TGT_TABLE_NAME FROM ODS_USER.CLNP WHERE CONTROLM=CTRLM AND APPL_CTGY=CTG AND APPL_SUB_CTGY= SBCT;
L_TGT_TABLE_NAME TBL_CUR%ROWTYPE;
BEGIN
OPEN TBL_CUR;
LOOP
FETCH TBL_CUR INTO L_TGT_TABLE_NAME;
V_TABLE:= L_TGT_TABLE_NAME.TGT_TABLE_NAME ;
EXIT WHEN TBL_CUR%NOTFOUND;
V_SQL:='DELETE FROM '||V_TABLE||' WHERE RPT_DT_ID'||'=:1';
EXECUTE IMMEDIATE V_SQL using RTDT;
END LOOP;
COMMIT;
CLOSE TBL_CUR;
END;

PL/SQL Printing Cursor Elements

I tried several ways and looked lots of codes, but I couldn't do it. I have 2 tables
Declare
v_ay varchar2(32);
cursor c_clone_time is
select beko_user_ref
from user_role;
begin
open c_clone_time;
fetch c_clone_time into v_ay
WHILE c_clone_time%FOUND LOOP
dbms_output.put_line (v_ay);
end while;
end;
I'm just trying to print the cursor values, but it is always failing. Can anyone help me ?
There are several spots(syntactical, semantical, and logical errors) in your code needed attention:
Minor one. The fetch c_clone_time into v_ay statement not terminated by semicolon ;.
You end while as any other loop statement with end loop; clause, not end while or end for as you might think.
To be able to print the contents of the cursor and successfully get out of the loop, you need to fetch from that cursor inside the loop as well, otherwise you are stuck with a never-ending loop:
Having said that your code might look look this:
declare
v_ay varchar2(32);
cursor c_clone_time is
select beko_user_ref
from user_role;
begin
open c_clone_time;
fetch c_clone_time into v_ay;
while c_clone_time%found loop
dbms_output.put_line (v_ay);
fetch c_clone_time into v_ay;
end loop;
end;
Test case:
create table user_role(
beko_user_ref varchar2(100)
);
insert into user_role(beko_user_ref)
select dbms_random.string('l', 7)
from dual
connect by level <= 7;
commit;
Print the cursor:
set serveroutput on;
clear screen;
declare
v_ay varchar2(32);
cursor c_clone_time is
select beko_user_ref
from user_role;
begin
open c_clone_time;
fetch c_clone_time into v_ay;
while c_clone_time%found loop
dbms_output.put_line (v_ay);
fetch c_clone_time into v_ay;
end loop;
end;
Result:
anonymous block completed
kcjhygy
cgunlmt
ofxaspd
qwqvnxx
nxjdrli
luevaqk
xvdocpr

Resources