※內部子程序
※Procedure裡面還有兩個Procedure
CREATE OR REPLACE PROCEDURE dept_ins_proc( xxx_dno DEPT.DEPTNO%TYPE, xxx_dname DEPT.DNAME%TYPE, xxx_loc DEPT.LOC%TYPE, xxx_rtn OUT BOOLEAN ) IS xxx_count NUMBER; PROCEDURE dept_count_proc( ooo_dno DEPT.DEPTNO%TYPE, ooo_count OUT NUMBER )IS BEGIN SELECT COUNT(DEPTNO) INTO ooo_count FROM DEPT WHERE DEPTNO = ooo_dno; END; -- END dept_count_proc; PROCEDURE dept_ins_do_proc( xox_dno DEPT.DEPTNO%TYPE, xox_dname DEPT.DNAME%TYPE, xox_loc DEPT.LOC%TYPE, xox_count NUMBER, xox_rtn OUT BOOLEAN )IS BEGIN IF xox_count > 0 THEN xox_rtn := FALSE; ELSE INSERT INTO DEPT VALUES(xox_dno, xox_dname, xox_loc); xox_rtn := TRUE; COMMIT; END IF; END; BEGIN DEPT_COUNT_PROC(xxx_dno, xxx_count); DEPT_INS_DO_PROC(xxx_dno, xxx_dname, xxx_loc, xxx_count, xxx_rtn); END; DECLARE rtn BOOLEAN; BEGIN DEPT_INS_PROC(50, '採購部', '芝加哥', rtn); IF rtn THEN DBMS_OUTPUT.PUT_LINE('true'); ELSE DBMS_OUTPUT.PUT_LINE('false'); END IF; END;
※因為使用DBMS印rtn會錯,只好這樣子寫了
※-- END dept_count_proc可以只寫END,但全寫比較清楚是什麼東西結束了
※尤於內部可以訪問外部,所以可以簡化,如下:
CREATE OR REPLACE PROCEDURE dept_ins_proc( xxx_dno DEPT.DEPTNO%TYPE, xxx_dname DEPT.DNAME%TYPE, xxx_loc DEPT.LOC%TYPE, xxx_rtn OUT BOOLEAN ) IS xxx_count NUMBER; PROCEDURE dept_count_proc IS BEGIN SELECT COUNT(DEPTNO) INTO xxx_count FROM DEPT WHERE DEPTNO = xxx_dno; END; PROCEDURE dept_ins_do_proc IS BEGIN IF xxx_count > 0 THEN xxx_rtn := FALSE; ELSE INSERT INTO DEPT VALUES(xxx_dno, xxx_dname, xxx_loc); xxx_rtn := TRUE; COMMIT; END IF; END; BEGIN DEPT_COUNT_PROC; DEPT_INS_DO_PROC(); END;
※此時最後的BEGIN和END就不需要傳參數了
※但子程序裡面的procedure不會出現在資料庫字典裡,所以只有自己能調用,如果需求是自己才需要,那就這樣子寫,不然還是要寫一隻在外面呼叫,所謂資料庫字典就是如下的樣子,圖片是集合的,procedure和function,在左邊是Procedures和Functions,右邊是程序和函數
※互相調用、重載(overloading)
互相調用就是a調用b,b也調用a重載就是方法名稱一樣,但參數個數或型態不同
※錯誤的例子
CREATE OR REPLACE PROCEDURE xxx(p NUMBER) IS -- PROCEDURE b_proc(p2 VARCHAR2); PROCEDURE a_proc(p1 NUMBER) IS BEGIN DBMS_OUTPUT.PUT_LINE('aaa'); b_proc('yeah!'); END; PROCEDURE b_proc(p2 VARCHAR2) IS BEGIN DBMS_OUTPUT.PUT_LINE('bbb'); a_proc(1); END; BEGIN a_proc(p); END; DECLARE BEGIN xxx(10); END;
※因為a調用b時,b還沒有定義,解法是將上面的註解打開就可以了
※但上面的程式碼沒給結束點,所以是個無限迴圈
※因為有支援重載,而上面的兩個procedure參數類型不同,所以名稱如果都一樣,也是可以執行的
※和集合配合
※以巢狀表為例
DECLARE TYPE xxx_nested IS TABLE OF EMP%ROWTYPE; xxx xxx_nested; FUNCTION dept_of_emp(edno EMP.DEPTNO%TYPE) RETURN xxx_nested IS ooo xxx_nested; BEGIN SELECT * BULK COLLECT INTO ooo FROM EMP WHERE DEPTNO = edno; RETURN ooo; END; BEGIN xxx := dept_of_emp(30); FOR i IN xxx.FIRST..xxx.LAST LOOP DBMS_OUTPUT.PUT_LINE(xxx(i).ENAME); DBMS_OUTPUT.PUT_LINE(xxx(i).JOB); DBMS_OUTPUT.put_line(xxx(i).SAL || CHR(10)); END LOOP; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('沒這個部門'); END;
※呼叫完後,跑迴圈印出
※遞歸
就是呼叫自己,所以如果不給一個結束點,就是無限迴圈※100以下的數字加到100的小程式
DECLARE FUNCTION x_to_hundred(i NUMBER) RETURN NUMBER IS xxx_sum NUMBER := 0; BEGIN IF i > 100 THEN RETURN xxx_sum; ELSE xxx_sum := i + x_to_hundred(i + 1); RETURN xxx_sum; END IF; END; BEGIN DBMS_OUTPUT.PUT_LINE(x_to_hundred(1)); END;
沒有留言:
張貼留言