Oracle procedure with SYS_REFCURSOR as OUT parameter displays only old values - sql

I created the following table called APP_USERS with nine columns:
I want to get all data from a single record by calling a procedure with SYS_REFCURSOR as OUT parameter: The code looks like that:
create or replace PACKAGE BODY USER_LOGIN AS
PROCEDURE getUserToLogIn(comp_id NUMBER, user_id APP_USERS.USER_ID%TYPE, pass APP_USERS.ACC_PASSWORD%TYPE, v_IS_ADMIN IN char,
curs out sys_refcursor)
IS
lala APP_USERS%ROWTYPE;
BEGIN
OPEN curs FOR
SELECT USER_ID,FIRST_NAME,MIDDLE_NAME,LAST_NAME,SEX,COMPANY_ID,IS_ADMIN,ACC_PASSWORD,IS_ACTIVE
FROM APP_USERS
WHERE COMPANY_ID = comp_id and USER_ID = TRIM(user_id) and ACC_PASSWORD = pass and IS_ADMIN = v_IS_ADMIN;
DBMS_OUTPUT.PUT_LINE(comp_id);
DBMS_OUTPUT.PUT_LINE(user_id);
DBMS_OUTPUT.PUT_LINE(pass);
DBMS_OUTPUT.PUT_LINE(v_IS_ADMIN);
DBMS_OUTPUT.PUT_LINE('--------------------------------------');
LOOP
FETCH curs INTO lala;
exit when curs%notfound;
DBMS_OUTPUT.PUT_LINE(lala.USER_ID);
DBMS_OUTPUT.PUT_LINE(lala.COMPANY_ID);
DBMS_OUTPUT.PUT_LINE(lala.ACC_PASSWORD);
DBMS_OUTPUT.PUT_LINE(lala.IS_ADMIN);
END LOOP;
CLOSE curs;
END getUserToLogIn;
END USER_LOGIN;
At first I called a procedure by running a simple anonymous block like below:
declare
curs sys_refcursor;
begin
USER_LOGIN.getUserToLogIn(1000,'EU1002','UCFE3M0N','N',curs);
end;
and I got the following results:
Next time I run the anonymous block again with wrong data, so that the procedure could not find them, but the result was not correct:
At first time, when I entered correct data my procedure displayed them, but the second attempt with wrong data entered caused displaying the data from the previous one.
My question is why:
exit when curs%notfound;
is this part of the code overlooked?

That not the proper way to use a refcursor. Here is a simplified example from your code:
create or replace PROCEDURE getUserToLogIn( user_id APP_USERS.USER_ID%TYPE,
curs in out sys_refcursor)
IS
BEGIN
OPEN curs FOR SELECT * FROM APP_USERS; -- where blah, blah
end ;
declare
lala APP_USERS%ROWTYPE;
my_cursor sys_refcursor;
begin
getUserToLogIn('xxx', my_cursor);
LOOP
FETCH my_cursor INTO lala;
exit when my_cursor%notfound;
DBMS_OUTPUT.PUT_LINE('output= ' || lala.USER_ID);
end loop;
close my_cursor;
end;
So the standard method is you call the procedure that creates the SELECT statement you need, then just OPEN cursor parameter. The caller then gets the cursor back, iterates thought it, then closes it.
Heres also a tutorial.

Related

How to display table from returned cursor in Oracle?

I need to get a table of bank's name which their bsb is equal to value given to the function.
Here is my code:
CREATE OR REPLACE Function FF(BSB_NUMBER IN BANK.BSB#%TYPE) RETURN SYS_REFCURSOR
IS
MY_CURSOR SYS_REFCURSOR;
BEGIN
OPEN MY_CURSOR for
select * from bank where bank.bsb# = BSB_NUMBER;
return MY_CURSOR;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Error ! There is no such account');
END FF;
/
And I run in with this but doesn't print anything. Appreciate any idea:
SELECT FindBankStaff(012878) FROM BANK;
Don't return the cursor, return the appropriate value.
Finally I saw this answer and implement it to my issue:
CREATE OR REPLACE FUNCTION SOME_FUNC_RETURNING_A_CURSOR RETURN SYS_REFCURSOR IS
csrLocal SYS_REFCURSOR;
BEGIN
OPEN csrLocal FOR SELECT NAME, BSB# FROM BANK;
RETURN csrLocal;
END SOME_FUNC_RETURNING_A_CURSOR;
/
DECLARE
aCursor SYS_REFCURSOR;
someVariable VARCHAR2(40);
some2 number;
BEGIN
aCursor := SOME_FUNC_RETURNING_A_CURSOR;
WHILE TRUE LOOP
FETCH aCursor INTO someVariable,some2;
EXIT WHEN aCursor%NOTFOUND;
DBMS_OUTPUT.PUT(someVariable);
DBMS_OUTPUT.PUT(' ');
DBMS_OUTPUT.PUT_LINE(some2);
END LOOP;
COMMIT;
END;
/
In Toad there is an option to do this.
You just have to create a bind variable as Ref cursor and invoke the procedure or function. Once the process runs successfully, the Data Grid is automatically populated with the result set of the Object (In your case the records from ref cursor). I suppose even in Oracle Sql Developer the Feature has been incorporated.
If you are using SQL Plus* then the best way is to declare a variable as ref cursor. Execute the piece of block and print the output using print command. Hope it helps...

Oracle pl/sql reference(return?) cursor/declared cursor

Is there a way to do something like this? Output a cursor's fetched data into a refcursor without stuffing it into a table first?
create or replace procedure someprocedure
(
rc1 in out adv_refcur_pkg.rc) -- this is defined below
as
v_class_year varchar(10);
cursor c1
is
select distinct e.pref_class_year
from entity e
where e.pref_class_year between i_start_class and i_end_class;
begin
open c1;
loop
fetch c1 into v_class_year;
EXIT WHEN c1%NOTFOUND;
end loop;
close c1;
open rc1 for select v_class_year from dual;
end;
here is the refcursor's declaration
CREATE OR REPLACE PACKAGE ADVANCE.adv_refcur_pkg
AS
TYPE RC IS REF CURSOR;
END adv_refcur_pkg;
According with this example, yes, it's possible:
https://forums.oracle.com/thread/696634
Why go to the trouble of doing that when you can simply pass the cursor itself?
create or replace procedure someprocedure
(
rc1 in out adv_refcur_pkg.rc) -- this is defined below
as
begin
open rc1 for
select distinct e.pref_class_year
from entity e
where e.pref_class_year between i_start_class and i_end_class;
end;
When you call "someprocedure", you have an open cursor you can then fetch from:
BEGIN
...
someprocedure(TheCursor);
LOOP
fetch TheCursor into v_class_year;
exit when TheCursor%NOTFOUND;
...
END LOOP;
CLOSE TheCursor;
...
END;

How can I fetch the data from the SYS_REFCURSOR from one stored proc and use it in another?

I have a stored proc with the basic layout below that returns a sys_refcursor as a result set. (Technically it reurns four but for the sake of clarity I just say one). The result set is a selection from a temp table.
procedure aProcedure
( C1 in out sys_refcursor
) is
begin
--populate Temp_Table here with a stored proc call;
OPEN C1 FOR
SELECT Cols
FROM TEMP_TABLE;
I need to insert this result set from C1 into a permanent table using a different stored procedure. Is this Do-able or do I need to re-build the result set all over again?
I've been able to find information on working with cursors and result sets outside of oracle but not for working with them within itself.
I know it might make sense to just do the insert from the first stored proc but that's not really how I need it to happen. It's an optional requirement to save the result set permanently.
Thanks for any helpful info.
Assuming that the caller knows the structure of the cursor that aProcedure is opening, you can do something like this.
declare
l_rc sys_refcursor;
l_rec temp_table%rowtype;
begin
aProcedure( l_rc );
loop
fetch l_rc
into l_rec;
exit when l_rc%notfound;
dbms_output.put_line( l_rec.col1 );
end loop;
close l_rc;
end;
/
If you can't fetch into a record type, you can also fetch into a number of other scalar local variables (the number and type have to match the number and type of columns that aProcedure specifies in its SELECT list). In my case, I defined aProcedure to return two numeric columns
declare
l_rc sys_refcursor;
l_col1 number;
l_col2 number;
begin
aProcedure( l_rc );
loop
fetch l_rc
into l_col1, l_col2;
exit when l_rc%notfound;
dbms_output.put_line( l_col1 );
end loop;
close l_rc;
end;

How to return a cursor populated with NESTED RECORD type from Oracle procedure

I need to return a cursor from Oracle procedure, the cursor has to contain RECORD types. I know how to solve this problem when the RECORD is simple, but how can this be solved for NESTED RECORDS?
There is a working block of code for simple RECORD:
-- create package with a RECORD type
create or replace package pkg as
-- a record contains only one simple attribute
type t_rec is RECORD (
simple_attr number
);
end;
/
-- create a testing procedure
-- it returns a cursor populated with pkg.t_rec records
create or replace procedure test_it(ret OUT SYS_REFCURSOR) is
type cur_t is ref cursor return pkg.t_rec;
cur cur_t;
begin
-- this is critical; it is easy to populate simple RECORD type,
-- because select result is mapped transparently to the RECORD elements
open cur for select 1 from dual;
ret := cur; -- assign the cursor to the OUT parameter
end;
/
-- and now test it
-- it will print one number (1) to the output
declare
refcur SYS_REFCURSOR;
r pkg.t_rec;
begin
-- call a procedure to initialize cursor
test_it(refcur);
-- print out cursor elements
loop
fetch refcur into r;
exit when refcur%notfound;
dbms_output.put_line(r.simple_attr);
end loop;
close refcur;
end;
/
Can you show me, how it could be done when a RECORD t_rec contains NESTED RECORD?
Modify the example in the folowing way:
-- create package with a NESTED RECORD type
create or replace package pkg as
type t_rec_nested is RECORD (
nested_attr number
);
-- a record with NESTED RECORD
type t_rec is RECORD (
simple_attr number,
nested_rec t_rec_nested
);
end;
/
create or replace procedure test_it(ret OUT SYS_REFCURSOR) is
type cur_t is ref cursor return pkg.t_rec;
cur cur_t;
begin
-- how to populate a result?
open cur for ????
ret := cur;
end;
/
The question is how to modify test_it procedure to populate a cursor?
I spent many hours searching the solution, I will appreciate any help.
I don't think it's possible as you have it, as RECORDs are a PL/SQL data type. You can do an equivalent thing by making an OBJECT. If you scroll down to the bottom of this link (or search for "Updating a Row Using a Record Containing an Object: Example" on the page), you will see how that is handled.

Get all records from a Ref Cursor in a Package

I'd like to fetch each row when I call the following function:
CpuReporting.getgridusage(300)
This function was provided in a CpuReporting package. It has:
Function GetGridUsage(minutes_Input in Number) Return CurGridUsage;
Type CurGridUsage is Ref Cursor Return RecGridUsage;
Type RecGridUsage is Record (ConfigId Number,
Phase VarChar2(400),
Environment VarChar2(400),
SessionStartTime Date,
I've browsed the GetGridUsage function in PL/SQL Developer, it has two parameters: (Result) REF CURSOR and MINUSTES_INPUT IN NUMBER
I want to be able to fetch all the rows and since I haven't worked with Ref Cursor before, I'm really interested in knowing how will you going to write the PL/SQL.
Assuming CpuReporting is the package name, you'd want something like
DECLARE
l_cursor CpuReporting.CurGridUsage;
l_rec CpuReporting.RecGridUsage;
BEGIN
l_cursor := CpuReporting.getGridUsage( 300 );
LOOP
FETCH l_cursor INTO l_rec;
EXIT WHEN l_cursor%notfound;
-- Do something with l_rec. As an example, print the Environment
dbms_output.put_line( l_rec.Environment );
END LOOP;
CLOSE l_cursor;
END;
If you just want to see the output of the function in PL/SQL you can do this
var r refcursor;
exec :r := CpuReporting.getgridusage(300);
print r;