在下面示例中,在包的使用環境中結合了在前面章節中討論的不同用戶定義類型。
包定義emp_rpt顯示了記錄類型 emprec_type以及弱類型REF CURSOR emp_refcur的聲明,這兩個類型與包中兩個函數和兩個存儲過程一樣,可以以公有方式訪問。函數open_emp_by_dept返回REF
CURSOR 類型 EMP_REFCUR存儲過程,fetch_emp和close_refur都聲明了一個弱類型的REF CURSOR作為形參。
CREATE OR REPLACE PACKAGE emp_rpt
IS
TYPE emprec_typ IS RECORD (
empno NUMBER(4),
ename VARCHAR(10)
);
TYPE emp_refcur IS REF CURSOR;
FUNCTION get_dept_name (
p_deptno IN NUMBER
) RETURN VARCHAR2;
FUNCTION open_emp_by_dept (
p_deptno IN emp.deptno%TYPE
) RETURN EMP_REFCUR;
PROCEDURE fetch_emp (
p_refcur IN OUT SYS_REFCURSOR
);
PROCEDURE close_refcur (
p_refcur IN OUT SYS_REFCURSOR
);
END emp_rpt;
包主體顯示了包中一些私有變量的聲明,包括一個靜態游標dept_cur, 一個表類型depttab_typ,一個表類型變量t_dept,一個整數變量t_dept_max和一個記錄類型r_emp。
CREATE OR REPLACE PACKAGE BODY emp_rpt
IS
CURSOR dept_cur IS SELECT * FROM dept;
TYPE depttab_typ IS TABLE of dept%ROWTYPE
INDEX BY BINARY_INTEGER;
t_dept DEPTTAB_TYP;
t_dept_max INTEGER := 1;
r_emp EMPREC_TYP;
FUNCTION get_dept_name (
p_deptno IN NUMBER
) RETURN VARCHAR2
IS
BEGIN
FOR i IN 1..t_dept_max LOOP
IF p_deptno = t_dept(i).deptno THEN
RETURN t_dept(i).dname;
END IF;
END LOOP;
RETURN 'Unknown';
END;
FUNCTION open_emp_by_dept(
p_deptno IN emp.deptno%TYPE
) RETURN EMP_REFCUR
IS
emp_by_dept EMP_REFCUR;
BEGIN
OPEN emp_by_dept FOR SELECT empno, ename FROM emp
WHERE deptno = p_deptno;
RETURN emp_by_dept;
END;
PROCEDURE fetch_emp (
p_refcur IN OUT SYS_REFCURSOR
)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH p_refcur INTO r_emp;
EXIT WHEN p_refcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(r_emp.empno || ' ' || r_emp.ename);
END LOOP;
END;
PROCEDURE close_refcur (
p_refcur IN OUT SYS_REFCURSOR
)
IS
BEGIN
CLOSE p_refcur;
END;
BEGIN
OPEN dept_cur;
LOOP
FETCH dept_cur INTO t_dept(t_dept_max);
EXIT WHEN dept_cur%NOTFOUND;
t_dept_max := t_dept_max + 1;
END LOOP;
CLOSE dept_cur;
t_dept_max := t_dept_max - 1;
END emp_rpt;
這個包主體包含了一個初始化部分,作用是通過使用私有靜態游標dept_cur,將私有表變量t_dept載入。而t_dept做為部門名稱在函數get_dept_name中查找表。
函數open_emp_by_dept根據指定部門編號為關于雇員號和雇員名稱的結果集返回一個REF CURSOR變量。這個REF CURSOR變量可以傳遞到存儲過程fetech_emp中,這樣存儲過程可以獲取和列出結果集的某一條記錄。最后,使用存儲過程close_refcur關閉和結果集相關的REF CURSOR變量。
下面的匿名代碼塊運行包的函數和存儲過程。在匿名塊的聲明部分中,要注意在聲明游標變量v_emp_cur時,使用了包的公有REF CURSOR類型EMP_REFCUR。v_empcur包含了結果集的指針,這個結果集可在包函數和存儲過程中傳遞。
DECLARE
v_deptno dept.deptno%TYPE DEFAULT 30;
v_emp_cur emp_rpt.EMP_REFCUR;
BEGIN
v_emp_cur := emp_rpt.open_emp_by_dept(v_deptno);
DBMS_OUTPUT.PUT_LINE('EMPLOYEES IN DEPT #' || v_deptno ||
': ' || emp_rpt.get_dept_name(v_deptno));
emp_rpt.fetch_emp(v_emp_cur);
DBMS_OUTPUT.PUT_LINE('**********************');
DBMS_OUTPUT.PUT_LINE(v_emp_cur%ROWCOUNT || ' rows were retrieved');
emp_rpt.close_refcur(v_emp_cur);
END;
下面是匿名代碼塊的輸出結果:
EMPLOYEES IN DEPT #30: SALES
EMPNO ENAME
----- -------
7499 ALLEN
7521 WARD
7654 MARTIN
7698 BLAKE
7844 TURNER
7900 JAMES
**********************
6 rows were retrieved
下面的匿名代碼塊演示了另外一種實現方法,也可以實現相同的結果。在匿名代碼塊中不使用包的存儲過程fetch_emp和close_refur,而是在把這些程序的實現邏輯直接編寫在匿名代碼塊中。在匿名代碼塊的聲明部分中,需要注意的是使用了包中公有記錄類型EMPREC_TYPE聲明的記錄型變量r_emp。
DECLARE
v_deptno dept.deptno%TYPE DEFAULT 30;
v_emp_cur emp_rpt.EMP_REFCUR;
r_emp emp_rpt.EMPREC_TYP;
BEGIN
v_emp_cur := emp_rpt.open_emp_by_dept(v_deptno);
DBMS_OUTPUT.PUT_LINE('EMPLOYEES IN DEPT #' || v_deptno ||
': ' || emp_rpt.get_dept_name(v_deptno));
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH v_emp_cur INTO r_emp;
EXIT WHEN v_emp_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(r_emp.empno || ' ' ||
r_emp.ename);
END LOOP;
DBMS_OUTPUT.PUT_LINE('**********************');
DBMS_OUTPUT.PUT_LINE(v_emp_cur%ROWCOUNT || ' rows were retrieved');
CLOSE v_emp_cur;
END;
下面是這個匿名代碼塊的執行結果:
EMPLOYEES IN DEPT #30: SALES
EMPNO ENAME
----- -------
7499 ALLEN
7521 WARD
7654 MARTIN
7698 BLAKE
7844 TURNER
7900 JAMES
**********************
6 rows were retrieved