Ref Cursor Examples
Ref Cursor Examples
create or replace
procedure a is
begin
null; -- a depends on nothing
end;
/
create or replace
procedure b is
begin
a; -- b depends on a
end;
/
create or replace
procedure c is
begin
b; -- c depends on b
end;
/
create or replace
procedure d is
begin
c; -- d depends on c
end;
/
create or replace
procedure e is
begin
a; -- e depends on a
d; -- and d
end;
/
a
|\
|b
||
|c
||
|d
|/
e
1
We can tell visually that the correct drop order would be 'e', 'd', 'c', 'b', 'a' - this is the
longest path.
The only object that can be dropped is 'e', because no other objects depend on it (ie it is not
referenced).
Refferring to step 3, we then select back child rows. ie rows which 'e' depend on. We can see
clearly that it will pull back 'a' and 'd'. But 'b' references 'a', so we can not drop it yet.
To do this properly, we would need some mechanism to exclude 'a', until all the objects that
depend
on it have been processed, but currently we can not use a sub-query in the connect-by clause.
So I'm afraid that (in my fallible opinion) it can not be done with one or two queries.
When you use native dynamic sql, most of the times you use execute
immediate statment and to this statement you pass your sql code which is
then executed.
When you use DBMS_SQL - you use a package that enables you to pass sql
code to Oracle engine. In this package you have procedure for opening
currsofr, fetching and so on...
Native Dynamic SLQ is easier to use because is integrated with sql, to
execute statment in PL/SQL you just write EXECUTE IMMEDIATE stmt, with
DBMS_SQL you have to use several procedures for exactly the same sql code.
Native is also faster than DBMS_SQL because you avoid overhead for calling
another packages (like in DBMS_SQL).
DBMS_SQL has also some advanteges over Native
for example you have functionality similar to describe command in SQL*Plus
DBMS_SQL supports code larger than 32K, native don't !!!
DBMS_SQL supports RETURNING clause for multirow statments native only for
single rows(i think about update or delete DML statment)
Since Oracle 7.3 REF CURSORS have been available which allow recordsets to be returned from
stored procedures, functions and packages. The example below uses a ref cursor to return a subset
of the records in the EMP table.
2
CREATE OR REPLACE
PROCEDURE GetEmpRS (p_deptno IN emp.deptno%TYPE,
p_recordset OUT Types.cursor_type) AS
BEGIN
OPEN p_recordset FOR
SELECT ename,
empno,
deptno
FROM emp
WHERE deptno = p_deptno
ORDER BY ename;
END GetEmpRS;
/
The resulting cursor can be referenced from PL/SQL as follows:
SET SERVEROUTPUT ON SIZE 1000000
DECLARE
v_cursor Types.cursor_type;
v_ename emp.ename%TYPE;
v_empno emp.empno%TYPE;
v_deptno emp.deptno%TYPE;
BEGIN
GetEmpRS (p_deptno => 30,
p_recordset => v_cursor);
LOOP
FETCH v_cursor
INTO v_ename, v_empno, v_deptno;
EXIT WHEN v_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_ename || ' | ' || v_empno || ' | ' || v_deptno);
END LOOP;
CLOSE v_cursor;
END;
/
declare
2 p_deptno number default 10;
3 begin
4 open :x for
5 'select deptno, dname, cursor( select ename from emp where
emp.deptno = dept.deptno
)
6 from dept
7 where deptno = :p_deptno' USING p_deptno;
8 end;
9 /
3
Oracle ref cursors allow you to define queries as stored procedures in the Database. They
can be used in java by executing a call through a callable statement to the stored
procedure and casting the returned ref. cursors to ResultSet.
Using the Reference cursors is a bit tricky. The following is the approach that allows
using the Reference cursors in Java Database programming.
Here is an example of a Stored Procedure using Ref Cursor.
/*
* Package Specification
*/
CREATE OR REPLACE PACKAGE REF_CURSOR_PROC
AS
// Declare reference cursor
TYPE CURSOR_TYPE IS REF CURSOR;
// register all the IN and OUT parameters,
// Note: To avoid the sensitivity of java drivers declare the OUT parameters
// after the IN parameters
PROCEDURE getMenu (
PRODUCT_TYPE IN VARCHAR2,
PRODUCT_CATEGORY IN VARCHAR2,
PRICE IN VARCHAR2,
RESULTS_MENU OUT CURSOR_TYPE
);
End REF_CURSOR_PROC;
/
Ravi Kumar B Page 4 1/20/2005 A white paper on Java Database Interaction Mechanism /*
* Declare Package Body
*/
CREATE OR REPLACE PACKAGE BODY REF_CURSOR_PROC
AS
/*
* Sequence of parameter declaration and signature must be same as
* Package specification.
*/
PROCEDURE getSubMenu (
PRODUCT_TYPE IN VARCHAR2, PRODUCT_CATEGORY IN VARCHAR2,
PRICE IN VARCHAR2,
RESULTS_SUB_MENU OUT CURSOR_TYPE
)
AS
BEGIN
/*
* Opening the reference cursor is very simple by stating a simple open
* Statement followed by FOR to hold the out put of the SQL query.
*/
OPEN RESULTS_SUB_MENU FOR
SELECT PMD.fkmenuid, MM.menuname, MM.cid, MM.SID, MM.hotflag, PMD.amount,
PMD.parentmenuid
FROM packagemenudetails PMD, menumaster MM
WHERE PMD.fkmenuid = MM.menuid
AND (MM.expiry_date IS NULL OR MM.expiry_date > SYSDATE)
AND PMD.parentmenuid = menu_id
4
AND PMD.fkpackageid = package_id
AND UPPER (PMD.fklanguageid) LIKE language_id
AND UPPER (MM.fkhandsetid) LIKE handset_id
ORDER BY PMD.menuitemsorder;
END getSubMenu;
END
5
Oracle/PLSQL: Procedure that outputs a dynamic PLSQL cursor
Question: In Oracle, I have a table called "wine" and a stored procedure that outputs a
cursor based on the "wine" table.
I've created an HTML Form where the user can enter any combination of three values to
retrieve results from the "wine" table. My problem is that I need a general "select"
statement that will work no matter what value(s), the user enters.
Example:
parameter_1= "Chianti"
parameter_2= "10"
parameter_3= wasn't entered by the user but I have to use in the select statement. And
this is my problem. How to initialize this parameter to get all rows for column3?
SELECT * FROM wine
WHERE column1 = parameter_1
AND column2 = parameter_2
AND column3 = parameter_3;.
The output of my stored procedure must be a cursor.
Answer: To solve your problem, you will need to output a dynamic PLSQL cursor in
Oracle.
Let's take a look at how we can do this. We've divided this process into 3 steps.
6
Step 3 - Create stored procedure
Our final step is to create a stored procedure to return the cursor. It accepts three
parameters (entered by the user on the HTML Form) and returns a cursor (c1) of type
"wine_type" which was declared in Step 2.
The procedure will determine the appropriate cursor to return, based on the value(s) that
have been entered by the user (input parameters).
create or replace procedure find_wine2
(col1_in in varchar2,
col2_in in varchar2,
col3_in in varchar2,
c1 out winepkg.wine_type)
as
BEGIN
/* all columns were entered */
IF (length(col1_in) > 0) and (length(col2_in) > 0) and (length(col3_in) > 0)
THEN
OPEN c1 FOR
select *
from wine
where wine.col1 = col1_in
and wine.col2 = col2_in
and wine.col3 = col3_in;
/* col1 and col2 were entered */
ELSIF (length(col1_in) > 0) and (length(col2_in) > 0) and (length(col3_in) = 0)
THEN
OPEN c1 FOR
select *
from wine
where wine.col1 = col1_in
and wine.col2 = col2_in;
/* col1 and col3 were entered */
ELSIF (length(col1_in) > 0) and (length(col2_in) = 0) and (length(col3_in) > 0)
THEN
OPEN c1 FOR
select *
from wine
where wine.col1 = col1_in
and wine.col3 = col3_in;
/* col2 and col3 where entered */
ELSIF (length(col1_in) = 0) and (length(col2_in) > 0) and (length(col3_in) > 0)
THEN
OPEN c1 FOR
select *
from wine
where wine.col2 = col2_in
and wine.col3 = col3_in;
/* col1 was entered */
ELSIF (length(col1_in) > 0) and (length(col2_in) = 0) and (length(col3_in) = 0)
THEN
OPEN c1 FOR
7
select *
from wine
where wine.col1 = col1_in;
/* col2 was entered */
ELSIF (length(col1_in) = 0) and (length(col2_in) > 0) and (length(col3_in) = 0)
THEN
OPEN c1 FOR
select *
from wine
where wine.col2 = col2_in;
/* col3 was entered */
ELSIF (length(col1_in) = 0) and (length(col2_in) = 0) and (length(col3_in) > 0)
THEN
OPEN c1 FOR
select *
from wine
where wine.col3 = col3_in;
END IF;
END find_wine2;
Oracle 9i Environment
8
15 END LOOP;
16 CLOSE cur0;
17 RETURN;
18 END OUT_FN;
19 /
Function created.
9
15 END LOOP;
16 CLOSE cur0;
17 RETURN;
18 END OUT_FN;
19 /
Function created.
DECLARE
P_CONS_REF sys_Refcursor;
cons_ref VARCHAR2(10);
sdo_cd VARCHAR2(4);
acc_no VARCHAR2(4);
BEGIN
EAUDIT.Ref_Cur1(P_CONS_REF );
LOOP
FETCH P_CONS_REF INTO CONS_REF,SDO_CD,ACC_NO ;
EXIT WHEN P_CONS_REF%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(CONS_REF||','||SDO_CD||','||ACC_NO);
END LOOP;
END;
With the REF_CURSOR you can return a recordset/cursor from a stored procedure.
There are 2 basic types: Strong ref cursor and weak ref cursor
For the strong ref cursor the returning columns with datatype and length need to be
10
known at compile time.
For the weak ref cursor the structure does not need to be known at compile time.
Since Oracle 9i you can use SYS_REFCURSOR as the type for the
returning
REF_CURSOR.
/* Strong type */
11
from emp
where deptno = p_deptno;
end test;
declare
type r_cursor is REF CURSOR;
c_emp r_cursor;
en emp.ename%type;
begin
open c_emp for select ename from emp;
loop
fetch c_emp into en;
exit when c_emp%notfound;
dbms_output.put_line(en);
end loop;
close c_emp;
end;
Let me explain step by step. The following is the first statement you need to
understand:
The above statement simply defines a new data type called "r_cursor," which
is of the type REF CURSOR. We declare a cursor variable named "c_emp"
based on the type "r_cursor" as follows:
c_emp r_cursor;
To retrieve each row of information from the cursor, I used a loop together
with a FETCH statement as follows:
loop
fetch c_emp into en;
12
exit when c_emp%notfound;
dbms_output.put_line(en);
end loop;
close c_emp;
declare
type r_cursor is REF CURSOR;
c_emp r_cursor;
er emp%rowtype;
begin
open c_emp for select * from emp;
loop
fetch c_emp into er;
exit when c_emp%notfound;
dbms_output.put_line(er.ename || ' - ' || er.sal);
end loop;
close c_emp;
end;
er emp%rowtype;
The above declares a variable named "er," which can hold an entire row from
the "emp" table. To retrieve the values (of each column) from that variable,
we use the dot notation as follows:
ref cursor is a data structure which points to an object which in turn points to the
memory location.
ex:
begin
13
type ref_cursor is ref cursor;
open ref_cursor as
end;
normal cursor:
it has 2 types
1. explicit cursor
2.Implicit cursor
A REF CURSOR is basically a data type. A variable created based on such a data type is
generally called a cursor variable. A cursor variable can be associated with different queries at
run-time. The primary advantage of using cursor variables is their capability to pass result
sets between sub programs (like stored procedures functions packages etc.).
Example :-
declare
type r_cursor is REF CURSOR;
c_emp r_cursor;
type rec_emp is record
(
name varchar2(20)
sal number(6)
);
er rec_emp;
procedure PrintEmployeeDetails is
begin
loop
fetch c_emp into er;
exit when c_emp notfound;
dbms_output.put_line(er.name || ' - ' || er.sal);
14
end loop;
end;
begin
for i in (select deptno dname from dept)
loop
open c_emp for select ename sal from emp where deptno i.deptno;
dbms_output.put_line(i.dname);
dbms_output.put_line('--------------');
PrintEmployeeDetails;
close c_emp;
end loop;
end;
15
REF CURSOR
A REF Cursor is a datatype that holds a cursor value in the same way that a VARCHAR2
variable will hold a string value.
A REF Cursor can be opened on the server and passed to the client as a unit rather than fetching
one row at a time. One can use a Ref Cursor as target of an assignment, and it can be passed
as parameter to other program units. Ref Cursors are opened with an OPEN FOR statement.
In most other ways they behave similar to normal cursors.
Example
Create a function that opens a cursor and returns a reference to it:
-----Call above function and fetch rows from the cursor it opened:
set serveroutput on
DECLARE
c SYS_REFCURSOR;
v VARCHAR2(1);
BEGIN
c := f(); -- Get ref cursor from function
FETCH c into v;
dbms_output.put_line('Value from cursor: '||v);
END;
--------=====================================
16
---======REF CURSOR USING IN FUNCTION ------
17