Sie sind auf Seite 1von 17

Consider the following schema :-

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;
/

This is my artists impression :-

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)

Using Ref Cursors To Return Recordsets

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.

First, a package definition is needed to hold the ref cursor type:


CREATE OR REPLACE PACKAGE Types AS
TYPE cursor_type IS REF CURSOR;
END Types;
/
Note. In Oracle9i the SYS_REFCURSOR type has been added making this first step unnecessary.
If you are using Oracle9i or later simply ignore this first package and replace any references to
Types.cursor_type with SYS_REFCURSOR.

Next a procedure is defined to use the ref cursor:

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 /

PL/SQL procedure successfully completed.

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

Example Stored Procedure


Collapse Copy Code
CREATE OR REPLACE
PROCEDURE GetEmpRS1 (p_recordset1 OUT SYS_REFCURSOR,
p_recordset2 OUT SYS_REFCURSOR,
PARAM IN STRING) AS
BEGIN
OPEN p_recordset1 FOR
SELECT RET1
FROM MYTABLE
WHERE LOOKUPVALUE > PARAM;

OPEN p_recordset2 FOR


SELECT RET2
FROM MYTABLE
WHERE LOOKUPVALUE >= PARAM;
END GetEmpRS1;
This stored procedure takes an input parameter for lookup, and has two OUT REF
CURSORS. For simplicity of this example, both the REF CURSORS return a column (a
single column). That is not a requirement in real life of course, you can as well associate
a REF CURSOR with a SELECT statement like: SELECT * ....

What is a REF CURSOR


Cursors, as you know, help return recordsets/ resultsets. There may be another more
technically correct definition of a cursor, but with my limited knowledge of databases,
that statement sounds correct. A SQL Server stored procedure can return "a resultset"
with a simple SELECT statement. It can even return multiple recordsets using multiple
SELECT statements. Can Oracle do that? Single recordset, of course. Multiple recordsets
- you need what is called a REF CURSOR. Treated just like a data type, your stored
procedure takes REF CURSORS as OUT parameters, and you can return a full recordset
in each REF CURSOR parameter back to the caller. So you can include as many REF
CURSOR parameters as you want - your stored procedure will have the ability to return
that many recordsets. Cool, huh?

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.

Step 1 - Table Definition


First, we need a table created in Oracle called "wine". Below is the create statement for
the wine table.
create table wine
( col1 varchar2(40),
col2 varchar2(40),
col3 varchar2(40)
);
We've made this table definition very simple, for demonstration purposes.

Step 2 - Create package


Next, we've created a package called "winepkg" that contains our cursor definition. This
needs to be done so that we can use a cursor as an output parameter in our stored
procedure.

create or replace PACKAGE winepkg


IS
/* Define the REF CURSOR type. */
TYPE wine_type IS REF CURSOR RETURN wine%ROWTYPE;
END winepkg;
This cursor will accept all fields from the "wine" table.

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

SQL> set serveroutput on


SQL> CREATE TYPE OUT_TY AS OBJECT (
2 COl1 VARCHAR2(1))
3 /
Type created.

SQL> CREATE TYPE OUT_TBL_TY AS TABLE OF OUT_TY;


2 /
Type created.

SQL> CREATE OR REPLACE FUNCTION OUT_FN


2 RETURN OUT_TBL_TY PIPELINED IS
3 PRAGMA AUTONOMOUS_TRANSACTION;
4 TYPE ref0 IS REF CURSOR;
5 cur0 ref0;
6 out_rec out_ty := out_ty(NULL);
7 BEGIN
8 OPEN cur0 FOR 'select dummy from dual';
9 LOOP
10 FETCH cur0 INTO out_rec.col1;
11 EXIT WHEN cur0%NOTFOUND;
12 dbms_output.put_line('Display from OUT_FN Line 1');
13 PIPE ROW(out_rec);
14 dbms_output.put_line('Display from OUT_FN Line 2');

8
15 END LOOP;
16 CLOSE cur0;
17 RETURN;
18 END OUT_FN;
19 /
Function created.

SQL> SELECT a.col1 FROM TABLE(OUT_FN) a


2 /
C
-
X

SQL> exec dbms_output.put_line('');


Display from OUT_FN Line 1
Display from OUT_FN Line 2

PL/SQL procedure successfully completed.

Oracle 10g Environment

SQL> set serveroutput on


SQL> CREATE TYPE OUT_TY AS OBJECT (
2 COl1 VARCHAR2(1))
3 /
Type created.

SQL> CREATE TYPE OUT_TBL_TY AS TABLE OF OUT_TY;


2 /
Type created.

SQL> CREATE OR REPLACE FUNCTION OUT_FN


2 RETURN OUT_TBL_TY PIPELINED IS
3 PRAGMA AUTONOMOUS_TRANSACTION;
4 TYPE ref0 IS REF CURSOR;
5 cur0 ref0;
6 out_rec out_ty := out_ty(NULL);
7 BEGIN
8 OPEN cur0 FOR 'select dummy from dual';
9 LOOP
10 FETCH cur0 INTO out_rec.col1;
11 EXIT WHEN cur0%NOTFOUND;
12 dbms_output.put_line('Display from OUT_FN Line 1');
13 PIPE ROW(out_rec);
14 dbms_output.put_line('Display from OUT_FN Line 2');

9
15 END LOOP;
16 CLOSE cur0;
17 RETURN;
18 END OUT_FN;
19 /
Function created.

SQL> SELECT a.col1 FROM TABLE(OUT_FN) a


2 /
C
-
X

Display from OUT_FN Line 1


Display from OUT_FN Line 2

CREATE OR REPLACE PROCEDURE Ref_Cur1 (p_cons_ref OUT sys_Refcursor)AS


BEGIN
OPEN p_cons_ref FOR SELECT cons_ref,sdo_cd,acc_no FROM
eaudit.EA_CONSUMER_CLUS WHERE sdo_cd = '1110' ;
END;
/

---calling ref cursor from sql prompt and TOAD.

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.

The STRONG_REF_CURSOR and until Oracle 9i also the weak-type need to be


declared in a package structure lik this:
create or replace package REFCURSOR_PKG as
TYPE WEAK8i_REF_CURSOR IS REF CURSOR;
TYPE STRONG_REF_CURSOR IS REF CURSOR RETURN EMP%ROWTYPE;
end REFCURSOR_PKG;

The pl/sql procedure that returns a ref-cursor looks like this:

/** until Oracle 9 */


create or replace procedure test( p_deptno IN number
, p_cursor OUT
REFCURSOR_PKG.WEAK8i_REF_CURSOR)
is
begin
open p_cursor FOR
select *
from emp
where deptno = p_deptno;
end test;

Since Oracle 9i you can use SYS_REFCURSOR as the type for the
returning
REF_CURSOR.

/** From Oracle 9 */


create or replace procedure test( p_deptno IN number
, p_cursor OUT SYS_REFCURSOR)
is
begin
open p_cursor FOR
select *
from emp
where deptno = p_deptno;
end test;

/* Strong type */

create or replace procedure test( p_deptno IN number


, p_cursor OUT
REFCURSOR_PKG.STRONG
REF_CURSOR)
is
begin
open p_cursor FOR
select *

11
from emp
where deptno = p_deptno;
end test;

Introduction to REF 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.).

Let us start with a small sub-program as follows:

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:

type r_cursor is REF CURSOR;

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;

Every cursor variable must be opened with an associated SELECT statement


as follows:

open c_emp for select ename from emp;

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;

I finally closed the cursor using the following statement:

close c_emp;

%ROWTYPE with REF CURSOR

In the previous section, I retrieved only one column (ename) of information


using REF CURSOR. Now I would like to retrieve more than one column (or
entire row) of information using the same. Let us consider the following
example:

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;

In the above example, the only crucial declaration is the following:

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:

dbms_output.put_line(er.ename || ' - ' || er.sal);

ref cursor is a data structure which points to an object which in turn points to the
memory location.

ex:

create or replace procedure test() as

begin

13
type ref_cursor is ref cursor;

open ref_cursor as

select * from table_name;

end;

There are 2 types in this.

1.strong ref cursor:

This has a return type defined.

2. weak ref cursor.

this doesnt have a return type

normal cursor:

Nothing but the named memory location.

it has 2 types

1. explicit cursor

Need to be defined whenever required.

2.Implicit cursor

need not defined and used by oracle implicitly in DML operation.

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.

This feature was introduced with PL/SQL v2.3 (Oracle 7.3).

Example
Create a function that opens a cursor and returns a reference to it:

CREATE OR REPLACE FUNCTION f


RETURN SYS_REFCURSOR
AS
c SYS_REFCURSOR;
BEGIN
OPEN c FOR select * from dual;
RETURN c;
END;

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

CREATE OR REPLACE FUNCTION func_ref_cur RETURN sys_refcursor AS


p_cons_ref sys_refcursor;
BEGIN
OPEN p_cons_ref FOR SELECT cons_ref,sdo_cd,acc_no FROM
eaudit.EA_CONSUMER_CLUS WHERE sdo_cd = '1110' ;
RETURN p_cons_ref;
END;

---CALLING REF CURSOR FROM SQL PROMPT


DECLARE
ret_val sys_Refcursor;
cons_ref VARCHAR2(10);
sdo_cd VARCHAR2(4);
acc_no VARCHAR2(4);
BEGIN
ret_val := func_ref_cur();
LOOP
FETCH RET_VAL INTO CONS_REF,SDO_CD,ACC_NO ;
EXIT WHEN RET_VAL%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(CONS_REF||','||SDO_CD||','||ACC_NO);
END LOOP;
END;

17

Das könnte Ihnen auch gefallen