You are on page 1of 6

The REF CURSOR is a data type in the Oracle.

REF CURSOR also referred as Cursor


Variables.Cursor variables are like pointers to result sets. Cursor can be attached
to only one query while REF CURSOR can be used to associate multiple queries at run
time.

Example :-
Declare
TYPE empcurtyp IS REF CURSOR RETURN emp%ROWTYPE;
refcur1 empcurtyp;
Begin
Open refcur1 for select * from emp;
Open refcur1 for select * from dept;
End;
REF CURSOR can be categorized into three

1. Strong Ref Cursor


Ref Cursors which has a return type is classified as Strong Ref Cursor.

Example :-

Declare
TYPE empcurtyp IS REF CURSOR RETURN emp%ROWTYPE;
�..
End;

Here empcurtyp is a Strong Ref Cursor

2. Weak Ref Cursor


Ref Cursors which has no return type is classified as Weak Ref Cursor.

Example :-

Declare
TYPE empcurtyp IS REF CURSOR;
�..
End;

Here empcurtyp is a Weak Ref Cursor

3. System Ref Cursor


This is a system defined Ref Cursor. This also considered weak. System Ref Cursor
need not declare explicitly.

Declare
empcurtyp SYS_REFCURSOR;
�..
End;

Advantages
1. Ref Cursor it self is a data type and easy to declare
2. More flexible because it is not tied to a specific query
3. Easily pass as arguments from subroutine to subroutine.
4. Very handy in transferring data between multi-language application (ex:- Java
and Oracle, Dot.net and Oracle, Oracle Forms and Oracle). Since it is a pointer to
the result set any client and server program can use the pointer to access the
data.
5. Cursor variables are bind variables ( Read more about BIND VARIABLES )

Dis-advantages
1. Ref Cursors are not efficient as StatiC Cursor
2. Need additional code to print Ref Cursor values

In general Ref Cursors are only be used when static cursor cannot do the work.

the REF CURSOR type has been available to allow recordsets to be returned from
stored procedures and functions. Oracle 9i introduced the predefined SYS_REFCURSOR
type, meaning we no longer have to define our own REF CURSOR types.

create or replace package pkg_refcur


is
� Declaring a Strong Ref Cursor Type
TYPE ref_strong_emptyp IS REF CURSOR RETURN emp%ROWTYPE;

� Declaring a Weak Ref Cursor Type


TYPE ref_weak_typ IS REF CURSOR;

�Package Signatures
procedure p_get_employees(pi_deptno in integer,
po_results out ref_strong_emptyp);

procedure p_get_dept_emp(pi_deptno in integer,


po_results out ref_weak_typ);

procedure p_get_deptemp(pi_deptno in integer,


po_results out sys_refcursor);

procedure p_getdeptemp(pi_deptno in integer,


pi_type in varchar2,
po_results out sys_refcursor);

procedure p_dynamic(pi_tablename in integer,


po_results out sys_refcursor);

End pkg_refcur;
/

create or replace package body pkg_refcur


is
� 1)
� Using Strong ref cursor to return employees in a department
procedure p_get_employees(pi_deptno in integer,
po_results out ref_strong_emptyp)
is
Begin
Open po_results for
select * from emp e
where e.deptno = pi_deptno;
Exception
when others then
raise;
End p_get_employees;

� 2)
� Using weak ref cursor to return employees and department details
procedure p_get_dept_emp(pi_deptno in integer,
po_results out ref_weak_typ)
is
Begin
Open po_results for
select * from emp e,dept d
where e.deptno = d.deptno
and e.deptno = pi_deptno;
Exception
when others then
raise;
End p_get_dept_emp;

� 3)
� Using system ref cursor to return employees and department details
procedure p_get_deptemp(pi_deptno in integer,
po_results out sys_refcursor)
is
Begin
Open po_results for
select * from emp e,dept d
where e.deptno = d.deptno
and e.deptno = pi_deptno;
Exception
when others then
raise;
End p_get_deptemp;

� 4)
� Associating multiple query
procedure p_getdeptemp(pi_deptno in integer,
pi_type in varchar2,
po_results out sys_refcursor)
is
Begin
if upper(pi_type) = �DEPT� then
Open po_results for
select * from emp e
where e.deptno = pi_deptno;
elsif upper(pi_type) = �EMP� then
Open po_results for
select * from dept e
where e.deptno = pi_deptno;
elsif upper(pi_type) = �BOTH� then
Open po_results for
select * from emp e,dept d
where e.deptno = d.deptno
and e.deptno = pi_deptno;
end if;
Exception
when others then
raise;
End p_getdeptemp;

� 5)
� Associating multiple query with dynamic query
procedure p_dynamic(pi_tablename in integer,
po_results out sys_refcursor)
is
Begin
if upper(pi_tablename) in (�EMP�,�DEPT�) then � for security
Open po_results for
�select * from � || pi_tablename ;
end if;
Exception
when others then
raise;
End p_dynamic;

End pkg_refcur;
/

Conclusion :- Ref Cursors are very ideal for interchanging data between two
different application involving Oracle as a database, like Java and Oracle, Dot net
and oracle, Oracle forms and Oracle etc.

REF CURSOR and SYS_REFCURSOR type is used interchangeably in PL/SQL program. With
respect to functionality or interpretation by processing engine there is no visible
difference between them.
However, from programmer point of view, the fundamental difference between is that
- programmer has to create type of REF CURSOR(weak or strong) and its variable
(called cursor variable) in their program unit (package body or anonymous block),
however SYS_REFCURSOR is predefined REF CURSOR defined in standard package of
Oracle located at following location in windows: %ORACLE_HOME
%/rdbms/admin/stdspec.sql
where %ORACLE_HOME% = C:\oraclexe_32bit\app\oracle\product\11.2.0\server\

SYS_REFCURSOR available from Oracle 9i onwards as part of standard package and weak
reference created for programmer easiness. Following declaration of SYS_REFCURSOR
from "stdspec.sql":
/* Adding a generic weak ref cursor type */
type sys_refcursor is ref cursor;
and while variable declaration we use SYS_REFCURSOR type .

Similarly, REF CURSOR type is created by programmer as part of program unit and
cursor variable is created using "cur_ref_type" type.
/*Cursor type declarator by programmer*/
type cur_ref_type is ref cursor;

Sample PL/SQL program to demonstrate differences between them, below is the stored
procedure that we want to execute using both SYS_REFCURSOR and REF CURSOR.
create or replace procedure get_employees_name(
v_deptId_in NUMBER,
v_cur OUT SYS_REFCURSOR )
--Note: SYS_REFCURSOR as parameter type used here because
--it has been declaredin standard package it is a ref cursor.
IS
begin
open v_cur for select FIRST_NAME,LAST_NAME from
employees where DEPARTMENT_ID = v_deptId_in;
end get_employees_name;

Execution by creating a custom cursor type- REF CURSOR - notice "type


custom_ref_cursor is ref cursor;" is used to create a cursor type and "v_cur
custom_ref_cursor;" is creating a variable out of it.
--using refcursor --
declare
-declare ref cursor type
type custom_ref_cursor is ref cursor;
v_fname VARCHAR2(10);
v_lname VARCHAR2(10);
v_cur custom_ref_cursor; -declare ref cursor variable
v_deptId_in NUMBER(2) := 90;
begin
HR.get_employees_name(v_deptId_in,v_cur);
dbms_output.put_line('FIRST_NAME' || ' ' || 'LAST_NAME');
dbms_output.put_line('---------------------------------');
LOOP
FETCH v_cur INTO v_fname, v_lname;
EXIT WHEN v_cur%NOTFOUND;
dbms_output.put_line(v_fname || ' ' || v_lname);
END LOOP;
CLOSE v_cur;
end;

Execution using standard cursor - SYS_REFCURSOR- here "type custom_ref_cursor is


ref cursor;" is commented and "v_cur SYS_REFCURSOR" is creating a cursor variable
using predefined cursor as SYS_REFCURSOR.
declare
--type rc is ref cursor; Not required
v_fname VARCHAR2(10);
v_lname VARCHAR2(10);
v_cur SYS_REFCURSOR;
--SYS_REFCURSOR used to create cursor variable
v_deptId_in NUMBER(2) := 90;
begin
HR.get_employees_name(v_deptId_in,v_cur);
dbms_output.put_line('FIRST_NAME' || ' ' || 'LAST_NAME');
dbms_output.put_line('---------------------------------');
LOOP
FETCH v_cur INTO v_fname, v_lname;
EXIT WHEN v_cur%NOTFOUND;

dbms_output.put_line(v_fname || ' ' || v_lname);


END LOOP;
CLOSE v_cur;
end;

Conclusion :- SYS_REFCURSOR is just a synonym for the REF CURSOR type.


SYS_REFCURSOR has been created as part of standard package just to discourage
boiler plate coding (in above created procedure get_employees_name- SYS_REFCURSOR
used as cursor type other wise we would have to create a cursor type and use it,
assume you have 100 similar procedure or function).Thanks Oracle for saving us from
hitting keyboard unnecessarily !!!

A cursor is a pointer to a result set for a query. By returning a sys_refcursor you


allow the client to fetch as many or few of the rows from the query as it requires.
In stateful applications this could be used to page through results.

A cursor can allow more flexibility than writing a PL/SQL function that returns an
array as it's completely up to the client how many rows to fetch and when to stop.
That said, I've not found many cases where this additional flexibility is useful.

It's worth noting that the sys_refcursor is weakly typed, so you can return
pointers to queries which not only have different from or where clauses, but
different numbers and types of columns as well. Alternatively you can use strongly
typed cursor where the columns in the result set are fixed.

This enables you to write functions which return different queries, like so:
create function get_data ( type varchar2 ) return sys_refcursor as
ret_cur sys_refcursor;
begin

if type = 'EMP' then


open ret_cur for select * from emp;
elsif type = 'DEPT' then
open ret_cur for select * from dept;
end if;

return ret_cur;
end;
However, if you're using sys_refcursor to create a generic "open a query" function
like the above you're probably doing something wrong!

1
down vote
As an example of the possibilities: because it's pl/sql in back, one can define an
object to represent a row, define a pl/sql table of those objects,

create type T_MY_TABLE as table of t_my_object;


and end with

OPEN p_recordset FOR select * from table( v_my_table );


So rather than constructing mongo, often dense and/or cryptic direct queries on a
database table, one can create an internal table and have the whole power of pl/sql
to populate it. And the client collecting the result-set is none the wiser. And
changing the definition of the internal table is easier from a management pov than
changing a database table.

Also when using report-generators like Jasper, you can push the SQL out of the
report and into the database, and just call the procedure to get the recordset,
leaving the report-side to focus on the formatting.

You might also like