承接入門篇,本文深入實戰技巧:多種執行方式、動態修改、DBMS_OUTPUT 除錯、OUT 參數回傳標量、REF CURSOR 回傳結果集、套件封裝,直指企業級開發需求。
-- 1. EXECUTE 命令 (SQL*Plus 專用)
EXECUTE skeleton;
-- 2. 匿名 PL/SQL 區塊 (通用,可在程式中嵌入)
BEGIN
skeleton;
END;
/
-- 3. 呼叫語法 (JDBC/ODP.NET/其他驅動標準)
CALL skeleton();
直接重跑 CREATE OR REPLACE PROCEDURE ... 即可**原子性替換**,無需先 DROP。正在執行的舊版本會跑完,新呼叫自動用新版本。
SQL> SET SERVEROUTPUT ON SIZE 1000000 -- 緩衝區 1MB,防截斷
SQL> EXECUTE debug_proc;
Debug: var_x = 42
PL/SQL procedure successfully completed.
生產環境建議改寫日誌表或 UTL_FILE 寫檔,避免緩衝區溢位影響效能。
CREATE OR REPLACE PROCEDURE get_dept_name (
p_deptno IN NUMBER,
p_dname OUT VARCHAR2
) IS
BEGIN
SELECT dname INTO p_dname FROM dept WHERE deptno = p_deptno;
EXCEPTION
WHEN NO_DATA_FOUND THEN p_dname := 'NOT FOUND';
END;
/
-- 呼叫
VARIABLE v_dname VARCHAR2(30);
EXECUTE get_dept_name(10, :v_dname);
PRINT v_dname;
CREATE OR REPLACE PACKAGE pkg_emp IS
TYPE ref_cursor IS REF CURSOR; -- 弱型,可對應任意查詢
PROCEDURE get_emps (p_deptno IN NUMBER, p_rc OUT ref_cursor);
END pkg_emp;
/
CREATE OR REPLACE PACKAGE BODY pkg_emp IS
PROCEDURE get_emps (p_deptno IN NUMBER, p_rc OUT ref_cursor) IS
BEGIN
OPEN p_rc FOR
SELECT empno, ename, sal
FROM emp
WHERE deptno = p_deptno
ORDER BY sal DESC;
END;
END pkg_emp;
/
-- SQL*Plus
VARIABLE rc REFCURSOR;
EXECUTE pkg_emp.get_emps(10, :rc);
PRINT rc;
-- Java (JDBC)
CallableStatement cs = conn.prepareCall("{call pkg_emp.get_emps(?, ?)}");
cs.setInt(1, 10);
cs.registerOutParameter(2, OracleTypes.CURSOR);
cs.execute();
ResultSet rs = (ResultSet) cs.getObject(2);
while (rs.next()) { ... }
c_max_retry CONSTANT NUMBER := 3;e_biz_error EXCEPTION; PRAGMA EXCEPTION_INIT(e_biz_error, -20001);FORALL + BULK COLLECT 減少 Context Switch。COMMIT,批次處理最後統一提交。OPEN ... FOR SELECT ...,勿先 BULK COLLECT INTO 再開游標 (雙重耗資源)。SQL*Plus 僅能 SHOW ERRORS。建議使用:
掌握 REF CURSOR、套件封裝、批次處理與現代化除錯工具,即可從「會寫存儲過程」進階為「寫出高效能、可維護的企業級 PL/SQL 系統」。