PL/SQL(Procedural Language/SQL)是 Oracle 對標準 SQL 的程序性擴展,深度整合於 Oracle Database 核心引擎中。自 Oracle 6 版起內建,已成為資料庫開發、管理自動化、高效能批次處理的核心工具。本文系統梳理 PL/SQL 核心優勢、區塊結構、命名與匿名區塊、可儲存程序單元(函數、程序、套件、觸發器),並深入解析宣告區的變數、常數、資料類型與複合型別。
GRANT/REVOKE 控制程序單元存取權限,實現資料存取封裝。
每個 PL/SQL 程式的基本單位是「邏輯區塊」,結構如下:
[DECLARE] -- 宣告區(選填):變數、常數、游標、例外、複合型別
BEGIN -- 執行區(必填):可執行陳述式、SQL、巢狀區塊
[EXCEPTION] -- 例外處理區(選填):錯誤捕捉與處理
END;
| 區段 | 關鍵字 | 內容 | 備註 |
|---|---|---|---|
| 宣告區 | DECLARE | 變數、常數、游標、使用者定義例外、記錄/集合型別 | 無宣告需求可省略 |
| 執行區 | BEGIN | 所有業務邏輯、SQL DML、流程控制、巢狀區塊 | 至少需一條可執行陳述式(NULL; 亦合法) |
| 例外區 | EXCEPTION | WHEN exception_name THEN ... 捕捉預定義/自訂例外 | 未捕捉例外將向外層傳播或終止區塊 |
語法細節:每條陳述式以分號結束;SQL 可跨行;單行可寫多條;區塊以 BEGIN 或 DECLARE 起始,END 結束;註解用 -- 或 /* ... */。
| 類型 | 關鍵字 | 回傳值 | 典型用途 | 呼叫方式 |
|---|---|---|---|---|
| 函數 | FUNCTION | 單一值(RETURN) | 計算、轉換、查詢單值 | SQL 陳述式中、PL/SQL 運算式中 |
| 程序 | PROCEDURE | 無(透過 OUT/IN OUT 參數回傳) | 執行動作、批次處理、DDL 封裝 | EXEC、CALL、PL/SQL 區塊內 |
| 套件 | PACKAGE | 無(含多個子程式) | 相關功能模組化、共享狀態、效能優化 | pkg_name.proc_name |
| 觸發器 | TRIGGER | 無 | 資料異動稽核、衍生欄位維護、安全稽核 | 隱含觸發(DML/DDL/系統事件) |
-- 函數
FUNCTION name [(param[, param...])] RETURN data_type IS
[local_declarations]
BEGIN
executable_statements
[EXCEPTION exception_handlers]
END [name];
-- 程序
PROCEDURE name [(param[, param...])] IS
[local_declarations]
BEGIN
executable_statements
[EXCEPTION exception_handlers]
END [name];
variable_name [CONSTANT] datatype [NOT NULL] [:= | DEFAULT expression]
CONSTANT 宣告常數,必須初始化且不可變更。NOT NULL 強制非空,宣告時必須給初值。:= 直接賦值、SELECT ... INTO / FETCH ... INTO 從查詢賦值。%TYPE 與 %ROWTYPE:資料字典驅動的型別安全| 屬性 | 用途 | 優勢 | 範例 |
|---|---|---|---|
%TYPE |
參考資料表欄位或另一變數的型別 | DDL 變更自動同步,免維護硬編碼型別 | v_empno emp.empno%TYPE; |
%ROWTYPE |
參考資料表完整列結構 | 一次宣告對應整列,SELECT * INTO 直觀 |
v_row emp%ROWTYPE; |
-- %TYPE 範例
DECLARE
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
BEGIN
SELECT empno, ename INTO v_empno, v_ename FROM emp WHERE empno = 7369;
DBMS_OUTPUT.PUT_LINE(v_empno || '/' || v_ename);
END;
-- %ROWTYPE 範例
DECLARE
v_row emp%ROWTYPE;
BEGIN
SELECT * INTO v_row FROM emp WHERE empno = 7369;
DBMS_OUTPUT.PUT_LINE(v_row.empno || '/' || v_row.ename || '/' || v_row.job);
END;
PL/SQL 提供兩大複合型別,對應高階語言的結構體與關聯陣列/字典:
TYPE rec_type IS RECORD (
field_name data_type [NOT NULL][:= default],
...
);
v_rec rec_type;
差異於 %ROWTYPE:欄位可自選、可異質、可加入非資料表欄位。
BINARY_INTEGER 或 VARCHAR2 驅動TYPE arr_type IS TABLE OF element_type INDEX BY BINARY_INTEGER;
v_arr arr_type;
特性:稀疏儲存、索引可為負數、支援 COUNT、FIRST、LAST、NEXT、PRIOR、DELETE、EXISTS 等集合方法。
-- 關聯陣列完整範例
DECLARE
TYPE emp_arr IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
v_emps emp_arr;
i PLS_INTEGER := 0;
BEGIN
FOR r IN (SELECT * FROM emp) LOOP
i := i + 1;
v_emps(i) := r;
END LOOP;
DBMS_OUTPUT.PUT_LINE('總筆數:' || v_emps.COUNT);
FOR j IN v_emps.FIRST .. v_emps.LAST LOOP
IF v_emps.EXISTS(j) THEN
DBMS_OUTPUT.PUT_LINE(v_emps(j).empno || ' ' || v_emps(j).ename);
END IF;
END LOOP;
END;
| 分類 | 常用型別 | 說明 |
|---|---|---|
| 數值 | NUMBER(p,s), BINARY_INTEGER, PLS_INTEGER | PLS_INTEGER 為機器整數運算,效能最佳 |
| 字元 | VARCHAR2(n), CHAR(n), CLOB, LONG | VARCHAR2 為變長首選,CHAR 定長補空白 |
| 日期時間 | DATE, TIMESTAMP, INTERVAL | DATE 含時分秒,TIMESTAMP 精度更高 |
| 布林 | BOOLEAN | 僅 PL/SQL 可用,SQL 不支援 |
| 二進位 | RAW, BLOB, BFILE | 大物件請用 LOB 型別,LONG RAW 已棄用 |
BLOB:二進位大物件(圖片、檔案)CLOB:字元大物件(長文本、XML、JSON)NCLOB:Unicode 字元大物件BFILE:唯讀外部檔案指標操作需使用 DBMS_LOB 套件,支援隨機存取,上限 4GB,優於已淘汰的 LONG 型別。
| 類別 | 運算子 | 備註 |
|---|---|---|
| 算術 | + - * / ** | ** 為冪運算 |
| 關係 | = != < > <= >= | 回傳 TRUE/FALSE/NULL |
| 比較 | LIKE, BETWEEN, IN, IS NULL | 同 SQL 語意 |
| 邏輯 | AND, OR, NOT | 三值邏輯(TRUE/FALSE/NULL) |
| 指派 | := | 唯一指派運算子 |
下篇預告:將深入執行區流程控制(條件、迴圈、標籤、GOTO)、例外處理機制、游標與大量收集、動態 SQL(EXECUTE IMMEDIATE/DBMS_SQL)等進階主題,敬請期待。