Some additional advantages of cursor variables are
Starting with Oracle7 release 7.3, you can use cursor variables in applications that run entirely in a single server session. You can declare cursor variables in PL/SQL subprograms, open them, and use them as parameters for other PL/SQL subprograms.
CREATE OR REPLACE PACKAGE emp_data AS TYPE emp_val_cv_type IS REF CURSOR RETURN emp%ROWTYPE; PROCEDURE open_emp_cv (emp_cv IN OUT emp_val_cv_type, dept_number IN INTEGER); PROCEDURE fetch_emp_data (emp_cv IN emp_val_cv_type, emp_row OUT emp%ROWTYPE); END emp_data; CREATE OR REPLACE PACKAGE BODY emp_data AS PROCEDURE open_emp_cv (emp_cv IN OUT emp_val_cv_type, dept_number IN INTEGER) IS BEGIN OPEN emp_cv FOR SELECT * FROM emp WHERE deptno = dept_number; END open_emp_cv; PROCEDURE fetch_emp_data (emp_cv IN emp_val_cv_type, emp_row OUT emp%ROWTYPE) IS BEGIN FETCH emp_cv INTO emp_row; END fetch_emp_data; END emp_data;
The following example shows how you can call the EMP_DATA package procedures from a PL/SQL block:
DECLARE -- declare a cursor variable emp_curs emp_data.emp_val_cv_type; dept_number dept.deptno%TYPE; emp_row emp%ROWTYPE; BEGIN dept_number := 20; -- open the cursor using a variable emp_data.open_emp_cv(emp_curs, dept_number); -- fetch the data and display it LOOP emp_data.fetch_emp_data(emp_curs, emp_row); EXIT WHEN emp_curs%NOTFOUND; DBMS_OUTPUT.PUT(emp_row.ename || ' '); DBMS_OUTPUT.PUT_LINE(emp_row.sal); END LOOP; END;
CREATE OR REPLACE PACKAGE emp_dept_data AS TYPE cv_type IS REF CURSOR; PROCEDURE open_cv (cv IN OUT cv_type, discrim IN POSITIVE); END emp_dept_data; / CREATE OR REPLACE PACKAGE BODY emp_dept_data AS PROCEDURE open_cv (cv IN OUT cv_type, discrim IN POSITIVE) IS BEGIN IF discrim = 1 THEN OPEN cv FOR SELECT * FROM emp WHERE sal > 2000; ELSIF discrim = 2 THEN OPEN cv FOR SELECT * FROM dept; END IF; END open_cv; END emp_dept_data;
You can call the OPEN_CV procedure to open the cursor variable and point it to either a query on the EMP table or on the DEPT table. How would you use this? The following PL/SQL block shows that you can fetch using the cursor variable, then use the ROWTYPE_MISMATCH predefined exception to handle either fetch:
DECLARE emp_rec emp%ROWTYPE; dept_rec dept%ROWTYPE; cv emp_dept_data.cv_type; BEGIN emp_dept_data.open_cv(cv, 1); -- open CV for EMP fetch FETCH cv INTO dept_rec; -- but fetch into DEPT record -- which raises ROWTYPE_MISMATCH DBMS_OUTPUT.PUT(dept_rec.deptno); DBMS_OUTPUT.PUT_LINE(' ' || dept_rec.loc); EXCEPTION WHEN ROWTYPE_MISMATCH THEN BEGIN DBMS_OUTPUT.PUT_LINE ('Row type mismatch, fetching EMP data...'); FETCH cv into emp_rec; DBMS_OUTPUT.PUT(emp_rec.deptno); DBMS_OUTPUT.PUT_LINE(' ' || emp_rec.ename); END; END;