How to edit a cursor attribute for a return statement on plsql? - sql

I want to return a cursor from a function, I have read that I can use:
return sys_refcursor
And then
open curs for select* from mytable;
return curs;
I tried curs.att := 'something' but I get an error
Also read I can do my own type:
TYPE type IS REF CURSOR RETURN mytable%ROWTYPE;
Then
CURSOR cur IS
SELECT* FROM mytable;
var cur%ROWTYPE;
BEGIN
OPEN cur;
FETCH cur INTO var;
var.att = 'something';
RETURN var;
This time I didn't get an error in the assign but in the return statement.
If I changed the var type to my type I couldn't fetch the value.
I wan't to edit the cursor, but not the table, how can I do this?

A cursor is a read-only structure. The only way to change the data that you would fetch from a cursor is to change the SQL statement that is used to open the cursor or to change the data in the underlying table(s).
While it is possible to return a cursor from one PL/SQL block to another, it is rarely the appropriate architecture. A SYS_REFCURSOR is generally appropriate when you want to return a result to a client application that knows how to use a cursor.
Do you really want to return a cursor, though? Or do you want to return a record type? The second code snippet you posted appears to be trying to return a record-- that's certainly possible but you would need to declare that the function returns a record rather than a cursor. That is, the RETURN statement in the declaration would need to be RETURN mytable%ROWTYPE rather than RETURN type. For example, if you want to return a record based on the EMP table
create or replace function get_emp( p_empno in emp.empno%type )
return emp%rowtype
is
l_rec emp%rowtype;
begin
select *
into l_rec
from emp
where empno = p_empno;
l_rec.sal := l_rec.sal + 100;
return l_rec;
end;

Related

Is this query returning a reference to a cursor?

I have a doubt about how a function returns a reference to a cursor in PostgreSQL. I have the following query :
CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS '
BEGIN
OPEN $1 FOR SELECT col FROM test;
RETURN $1;
END;
' LANGUAGE plpgsql;
BEGIN;
SELECT reffunc('funccursor');
FETCH ALL IN funccursor;
COMMIT;
Does this function return a reference to a cursor ? If not, how can I modify it to return a reference to a cursor ?
A refcursor variable contains the name of a cursor, a data structure that holds the active query.
See the documentation.
So yes, it is a reference to a cursor.

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...

Check Values in sys_refcursor

I have the following code in a function
CREATE OR REPLACE FUNCTION my_func (
v_dt events.raised_date%TYPE
)
RETURN SYS_REFCURSOR
IS
p_events SYS_REFCURSOR;
OPEN p_events FOR
SELECT event_id
FROM events
WHERE raised_date = v_dt;
RETURN p_events;
END;
I would like to check whether 100 exists in p_events cursor or not. How can I do this inside my function.
Any help is highly appreciable.
A ref cursor is just a pointer to query. There is nothing "in" it. So the only way to find out whether the result set identified by the ref cursor contains a specific record - or indeed any records - is to fetch the cursor and read through the records.
Bear in mind that a ref cursor is a one-shot thang. We cannot fetch the same cursor more than once. We have to close and re-open it. But that means we run the risk of the second fetched result set differing from the first (unless we change the transaction's isolation level).
So the upshot is, just code the consuming procedure to fetch and use the ref cursor, and make sure it handles both the presence and absence of interesting records.
It is not good idea to check it inside of the function. You are missing why the cursor is returned. Instead do it outside of the function.
DECLARE
l_rc SYS_REFCURSOR := my_func();
TYPE events_ntt IS TABLE OF NUMBER;
l_events events_ntt;
l_lookup events_ntt := events_ntt(100);
l_diff events_ntt;
BEGIN
FETCH l_rc BULK COLLECT INTO l_events;
l_diff := l_events MULTISET INTERSECT DISTINCT l_lookup;
IF l_diff.COUNT > 0 THEN
DBMS_OUTPUT.PUT_LINE('100 EXISTS');
ELSE
DBMS_OUTPUT.PUT_LINE('100 DOES NOT EXIST');
END IF;
END;
Using Cursor Variables (REF CURSORs)
Like a cursor, a cursor variable points to the current row in the
result set of a multi-row query. A cursor variable is more flexible
because it is not tied to a specific query. You can open a cursor
variable for any query that returns the right set of columns.
You pass a cursor variable as a parameter to local and stored
subprograms. Opening the cursor variable in one subprogram, and
processing it in a different subprogram, helps to centralize data
retrieval. This technique is also useful for multi-language
applications, where a PL/SQL subprogram might return a result set to a
subprogram written in a different language, such as Java or Visual
Basic.
What Are Cursor Variables (REF CURSORs)?
Cursor variables are like pointers to result sets. You use them when
you want to perform a query in one subprogram, and process the results
in a different subprogram (possibly one written in a different
language). A cursor variable has datatype REF CURSOR, and you might
see them referred to informally as REF CURSORs.
Unlike an explicit cursor, which always refers to the same query work
area, a cursor variable can refer to different work areas. You cannot
use a cursor variable where a cursor is expected, or vice versa.
Source: http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/sqloperations.htm#i7106
(Oracle Database PL/SQL User's Guide and Reference)
It can be done like this
declare
evt EVENTS%ROWTYPE;
found_100 boolean := false;
begin
loop
fetch p_events into evt;
exit when p_events%NOTFOUND;
if evt.event_id = 100 then
found_100 := true;
exit;
end if;
end loop;
end;
but however it's very inefficient because you're possibly fetching millions of records where you actually only need 1 fetch.

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.

How to return rows from a declare/begin/end block in Oracle?

I want to return rows from a select statement within a declare/begin/end block. I can do this in T-SQL but I would like to know how to do it in PL/SQL.
The code looks a bit like the following:
declare
blah number := 42;
begin
select *
from x
where x.value = blah;
end;
An anonymous PL/SQL block, like the one you've shown, can't "return" anything. It can interact with the caller by means of bind variables, however.
So the method I would use in this case would be to declare a cursor reference, open it in the PL/SQL block for the desired query, and let the calling application fetch rows from it. In SQLPlus this would look like:
variable rc refcursor
declare
blah number := 42;
begin
open :rc for
select *
from x
where x.value = blah;
end;
/
print x
If you recast your PL/SQL as a stored function then it could return values. In this case what you might want to do is create a collection type, fetch all the rows into a variable of that type, and return it:
CREATE TYPE number_table AS TABLE OF NUMBER;
CREATE FUNCTION get_blah_from_x (blah INTEGER)
RETURN number_table
IS
values number_table;
BEGIN
SELECT id
BULK COLLECT INTO values
FROM x
WHERE x.value = blah;
RETURN values;
END;
/
Well, this depends heavily on your data access library.
You can return any SQL-compatible type as a parameter. This includes complex SQL types and collection types.
But most libraries are simply not capable of handling Oracle's object types.
Either way, my examples will use these object types:
create type SomeType as object(Field1 VarChar(50));
create type SomeTypeList as table of SomeType;
When your access library can handle object types, you could simply return a list of PL/SQL objects:
begin
:list := SomeTypeList(SomeType('a'),SomeType('b'),SomeType('c'));
end;
If not, you could hack around it by forcing this list into a select and return its result as a cursor:
declare
list SomeTypeList;
begin
list := SomeTypeList(SomeType('a'),SomeType('b'),SomeType('c'));
open :yourCursor for
SELECT A
FROM table(list);
end;