Sei sulla pagina 1di 7

REF CURSOR

REF CURSOR is nothing but a dynamic cursor which points a select statement at run
time. So we can have multiple select statements defined for a particular cursor unlike
static cursors.

There are basically two types of REF cursors:

1 STRONG REF CURSOR

2 WEAK REF CURSOR

STRONG REF CURSOR

STRONG REF CURSORS are those ref cursors that have a return type defined.
The structure of the SELECT statement (the number and datatypes of the columns) must
match or be compatible with the structure specified in the RETURN clause of the cursor
type declaration statement.

DECLARE
TYPE cur_ref is REF CURSOR RETURN employees%rowtype;
c1 cur_ref; --CURSOR VARIABLE
DECLARATION
er employees%rowtype;
BEGIN

OPEN c1 FOR SELECT * FROM EMPLOYEES;


LOOP
fetch c1 into er;
dbms_output.put_line('FOR 1ST CURSOR'||er.last_name);
exit when(c1%NOTFOUND);
END LOOP;
close c1;

OPEN c1 FOR SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID=101;


LOOP
fetch c1 into er;
dbms_output.put_line('FOR 2ND CURSOR'||er.last_name);
exit when(c1%NOTFOUND);
END LOOP;
close c1;
END;
We can define multiple select statements here for cursor c1 but of only employees row
type as we have mentioned the return type to be of employees type. For any type of select
statements we can use weak ref cursors.

WEAK REF CURSOR

Weak ref cursors can be used for any type of select statements unlike strong ref cursors.
This is because we don't have a return type declared for the type statements.

DECLARE
TYPE cur_REF is REF CURSOR ;
c1 cur_ref;
er employees%rowtype;
BEGIN
OPEN c1 FOR SELECT * FROM EMPLOYEES;
LOOP
fetch c1 into er;
dbms_output.put_line(('FOR 1ST CURSOR'||er.last_name);
exit when(c1%NOTFOUND);
END LOOP;
close c1;
OPEN c1 FOR SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID=101;
LOOP
fetch c1 into er;
dbms_output.put_line(('FOR 2ND CURSOR'||er.last_name);
exit when(c1%NOTFOUND);
END LOOP;
close c1;
OPEN c1 FOR SELECT * FROM DEPARTMENTS;
LOOP
fetch c1 into er;
dbms_output.put_line(('FOR 3RD CURSOR'|er.last_name);
exit when(c1%NOTFOUND);
END LOOP;
close c1;
END;

So just a simple rule for coding with ref cursor is to declare a type ref cursor. Assign it to
a cursor variable.While opening the cursor attach a for select statement with it. Thats it .
And everything else remains same as it is for a code developed using static cursors.

Now it depends on you how to use them.

Use strong type ref cursor if you need records to be fetched from a particular type of
table.
Use weak ref cursor if you are going to fetch record from different tables with different
datatypes and columns.

Composite Datatypes Introduction to Oracle


SQL & PL/SQL
Updated 11/5/2001

• Concepts
• PL/SQL Records
o Using %ROWTYPE
• PL/SQL Tables
o Creating a PL/SQL table
o Using a PL/SQL table
o PL/SQL Table Methods

Concepts

• Oracle allows you to define several kinds of composite datatypes, also knows as
collections, including RECORD, PL/SQL TABLE, Nested Table, and VARRAY.
• A composite datatype is different from a scalar datatype in that a composite datatype has
an internal structure.
• We will over PL/SQL records and PL/SQL Tables

PL/SQL Records

• A record is a group of related data items stored in fields, each with its own name and
datatype.
• The structure of a record can be declared explicitly, or declared based on a cursor or
database table.
• Creating a user defined record is a two step process, you first declare a record type and
the declare a record based on that type.

DECLARE
--Create a record type. Note similarity to table
creation syntax.
TYPE emp_record_type IS RECORD
empno NUMBER(10),
ename VARCHAR2(10),
job VARCHAR2(9),
sal NUMBER(8,2));

--Create an record named EMP_RECORD based on the


structure above
emp_record emp_record_type;
BEGIN
...
END;
DECLARE
--Create a record type. Note similarity to table
creation syntax.
TYPE emp_record_type IS RECORD
empno NUMBER(10) NOT NULL:=0, --NOT NULL fields must
be initialized
ename VARCHAR2(10),
job VARCHAR2(9):='CLERK',
sal NUMBER(8,2));
--Create an record named EMP_RECORD based on the
structure above
emp_record emp_record_type;
BEGIN
...
END;

Using %ROWTYPE

DECLARE
dept_record dept%ROWTYPE;
/* The dept record will have the following structure:
* DEPTNO, NUMBER(2)
* DNAME, VARCHAR2(14)
* LOC, VARCHAR2(13)
*/
BEGIN
...
END;

• There is a small overhead (performance penalty) when using the %ROWTYPE attribute
with anonymous PL/SQL blocks.
• The values within a record type can be assigned or referenced like so

record_name.field_name

emp_record.ename:='GATES';

v_header:=emp_record.ename || ' works in '||


dept_record.loc;
• Identical record types can be assigned to each other directly.

DECLARE

dept_record1 dept%ROWTYPE;
--base this record structure on the first record
structure
dept_record2 dept_record1%ROWTYPE;
CURSOR dept_cursor IS
SELECT *
FROM dept;
BEGIN
OPEN dept_cursor;
FETCH dept_cursor INTO dept_record1;
CLOSE dept_cursor;
dept_record2:=dept_record1; --assign from one record to
the other.
DBMS_OUTPUT.PUT_LINE(dept_record2.dname);
END;
/
• Note that a user defined record and a record anchored to a database table may have a
compatible datatype, if they match in number, name, and datatype of fields. SInce they
have compatible datatypes, the values can be directly assigned from one row to another.

DECLARE
dept_record1 dept%ROWTYPE;
TYPE dept_record_type IS RECORD (
deptno NUMBER(2),
dname VARCHAR2(14),
loc VARCHAR2(13));
dept_record2 dept_record_type;
CURSOR dept_cursor IS
SELECT *
FROM dept;
BEGIN
OPEN dept_cursor;
FETCH dept_cursor INTO dept_record1;
CLOSE dept_cursor;
dept_record2:=dept_record1; --assign from one record to
the other.
DBMS_OUTPUT.PUT_LINE(dept_record2.dname);
END;
/

PL/SQL Tables

• PL/SQL tables are:


o One dimensional.
o Unbounded.
o Sparse.
o Homogenous.
o Indexed by integer.
• PL/SQL Tables are quite different from database tables
o PL/SQL do not recognize any SQL statements: PL/SQL are referenced a-row-at-
a-time not a-set-at-a-time as in SQL.
o PL/SQL tables do not participate in transactions.
o Database tables exist on disk; PL/SQL tables exist in memory. Therefore
accessing information in PL/SQL tables can be much faster than in database
tables.

Creating a PL/SQL table

Creating a PL/SQL table is a two step process, first you declare the table type, and then declare
an identifier using that type.
DECLARE
TYPE ename_table_type IS
--This defines the datatype and size of the column.
In this case its anchored to ENAME.
TABLE OF emp.ename%TYPE
--Each row in a PL/SQL table is identified by a
BINARY_INTEGER.
INDEX BY BINARY_INTEGER;
--This creates a table named ename_table with the
structure defined above.
ename_table ename_table_type;
BEGIN
...
END;
/

Using a PL/SQL table

You can assign and reference elements in a PL/SQL table using an integer to identify the specific
row.

ename_table(1):='My name';

v_grade_report:='Report for '||ename_table(10);

You can navigate a PL/SQL table with the following methods

PL/SQL Table Methods


table_name.EXISTS(n)
table_name.COUNT
table_name.FIRST / table_name.LAST
table_name.PRIOR(n)
table_name.NEXT(n)

• An example using some of the built in methods:

DECLARE
TYPE ename_table_type IS TABLE OF emp.ename%TYPE
INDEX BY BINARY_INTEGER;
ename_table ename_table_type;
v_index BINARY_INTEGER:=1;

BEGIN
FOR emp_record IN (SELECT * FROM emp) LOOP
ename_table(v_index):=emp_record.ename;
v_index:=v_index+1;
END LOOP;
v_index:=ename_table.FIRST;
WHILE ename_table.EXISTS(v_index) LOOP
DBMS_OUTPUT.PUT_LINE('ename_table('||v_index||') '||
ename_table(v_index));
v_index:=ename_table.NEXT(v_index);
END LOOP;
END;
/
• You can create a PL/SQL table of records like so:

DECLARE
TYPE ename_table_type IS
TABLE OF emp%ROWTYPE --PL/SQL column is a record
based on the EMP table.
INDEX BY BINARY_INTEGER;
ename_table ename_table_type;
v_index BINARY_INTEGER:=1;

BEGIN
FOR emp_record IN (SELECT * FROM emp) LOOP
ename_table(v_index):=emp_record;
/* Of course, you could also assign values like so:
* ename_table(v_index).ename:=emp_record.ename;
* ename_table(v_index).job:=emp_record.job;
*/
v_index:=v_index+1;
END LOOP;
v_index:=ename_table.FIRST;
WHILE ename_table.EXISTS(v_index) LOOP
DBMS_OUTPUT.PUT_LINE('ename_table('||v_index||') '
||ename_table(v_index).ename||' is a '||
ename_table(v_index).job);
v_index:=ename_table.NEXT(v_index);
END LOOP;
END;
/

Potrebbero piacerti anche