※包
.可以將procedure、function、cursor…等包起來一起管理,分成包和包體.可以將包想成java的interface,而包體就是實作interface的class
.如果包沒定義,而包體寫了,外面就沒辦法訪問,就像是class雖然實作了interface,但裡面又定義了private的方法一樣,只有自己能調用
※宣告包
CREATE OR REPLACE PACKAGE xxx_pkg IS -- TYPE xxx_cur IS REF CURSOR; FUNCTION dept_of_emp(xxx_dno DEPT.DEPTNO%TYPE) RETURN SYS_REFCURSOR; -- RETURN xxx_cur; -- PROCEDURE aaa; -- CURSOR bbb RETURN DEPT%ROWTYPE; -- CURSOR ccc RETURN DEPT%ROWTYPE IS -- SELECT * FROM DEPT WHERE DEPTNO = 20; END;
※上面是系統定義的弱游標類型,如果要自己定義弱游標,就將第一個註解打開,然後回傳值就是自定義的即可(就是第二個註解)
※剩下的註解就是可以定很多的意思,如procedure、function…等,和java不一樣的地方是它也可以定出內容,如最後的ccc,這樣子實作它的包體就可以直接拿來用,不用實作了
※宣告包體
CREATE OR REPLACE PACKAGE BODY xxx_pkg IS
FUNCTION dept_of_emp(xxx_dno DEPT.DEPTNO%TYPE)
RETURN SYS_REFCURSOR
-- RETURN xxx_cur
IS
ooo_cur SYS_REFCURSOR;
-- ooo_cur xxx_cur;
BEGIN
OPEN ooo_cur FOR SELECT * FROM EMP WHERE DEPTNO = xxx_dno;
RETURN ooo_cur;
CLOSE ooo_cur;
END dept_of_emp;
PROCEDURE aaa IS
BEGIN
DBMS_OUTPUT.PUT_LINE('aaa');
END aaa;
END;
※注意包體第一行變成PACKAGE BODY,有BODY喔!
※註解的部分是自定弱游標的寫法
※測試
DECLARE ooo_cur SYS_REFCURSOR; -- ooo_cur xxx_pkg.xxx_cur; xxx_emp EMP%ROWTYPE; BEGIN -- xxx_pkg.aaa; ooo_cur := xxx_pkg.dept_of_emp(20); /* FETCH ooo_cur INTO xxx_emp; WHILE ooo_cur%FOUND LOOP DBMS_OUTPUT.PUT_LINE(xxx_emp.ename); FETCH ooo_cur INTO xxx_emp; END LOOP; */ LOOP FETCH ooo_cur INTO xxx_emp; EXIT WHEN ooo_cur%NOTFOUND; DBMS_OUTPUT.PUT_LINE(xxx_emp.ename); END LOOP; CLOSE ooo_cur; END;
※如果是自定弱游標的類型,就要寫成「包.游標」
※xxx_pkg.aaa這一行必需在包有定義,不然就是最前面說的,只是個內部能調用的方法
※兩種迴圈都可以用,但我試FOR迴圈會錯,不知道為什麼
※USER_OBJECTS、USER_SOURCE這兩張表可以看到宣告的一些資訊
※刪除包和包體
DROP PACKAGE package名稱;DROP PACKAGE BODY package名稱;
※重載和Session
就是包裡面可以有同樣的名稱,但參數個數或類型不同CREATE OR REPLACE PACKAGE xxx_pkg IS -- PRAGMA SERIALLY_REUSABLE; ooo VARCHAR2(10) := 'ooo'; PROCEDURE xxx(p EMP.ENAME%TYPE); PROCEDURE xxx(p EMP.EMPNO%TYPE); PROCEDURE xxx(p1 EMP.EMPNO%TYPE, p2 EMP.ENAME%TYPE); END;
※宣告一個變數和三個procedure
CREATE OR REPLACE PACKAGE BODY xxx_pkg IS
-- PRAGMA SERIALLY_REUSABLE;
PROCEDURE xxx(p EMP.ENAME%TYPE) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('ename:' || p);
DBMS_OUTPUT.PUT_LINE('ooo:' || ooo);
END;
PROCEDURE xxx(p EMP.EMPNO%TYPE) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('empno:' || p);
ooo := 'xxx';
DBMS_OUTPUT.PUT_LINE('ooo:' || ooo);
END;
PROCEDURE xxx(p1 EMP.EMPNO%TYPE, p2 EMP.ENAME%TYPE) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('2個參數:' || p1 || '和' || p2);
DBMS_OUTPUT.PUT_LINE('ooo:' || ooo);
END;
END;
※一個參數的EMPNO改變ooo變數的值
※測試
DECLARE
BEGIN
-- xxx_pkg.ooo := 'aaa';
-- xxx_pkg.xxx('xyz');
-- xxx_pkg.xxx(123);
xxx_pkg.xxx(321, 'zyx');
END;
※重點在xxx_pkg.ooo,如果打開後執行三個隨便一個procedure,然後再關閉xxx_pkg.ooo,這時會發現不是預設的ooo,因為這相當於全域變數的關係,解決方法有兩個,一種就是將視窗關閉再打開執行就可以了,因為視窗關閉,此session就關閉了
另一種方法是將PACKAGE和PACKAGE BODY的註解打開(就是PRAGMA SERIALLY_REUSABLE),這樣就可以每次都幫我們加載-缷載的動作了,不過較浪費效能,所以不建議使用
沒有留言:
張貼留言