SQL 本質上是面向集合的宣告式語言,但 Oracle 在長期演進中大量吸收了面向物件的設計思想。這並非矛盾,而是為了讓開發者以更直觀、更高效的方式處理複雜業務。本文從游標、套件、集合操作三個維度,剖析 Oracle 如何在集合基因中融入物件導向基因。
游標是處理結果集的指標,其 FOR ... IN 語法極類似 C# foreach 或 Java 增強 for 迴圈:
BEGIN
FOR student IN (SELECT sid, name, age, hobby FROM my_test) LOOP
DBMS_OUTPUT.PUT_LINE('學號:' || student.sid || ' 姓名:' || student.name);
END LOOP;
END;
student 隱性宣告為 cursor%ROWTYPE 記錄型別,直接以 student.sid 存取屬性 —— 這是典型的物件屬性存取語法。CURSOR c(p_deptno NUMBER) IS SELECT ... WHERE deptno=p_deptno 相當於帶參數的迭代器工廠方法。Oracle 套件由 規格**與**主體** 組成,完美對應介面與實現分離:
-- 規格(公開介面)
CREATE OR REPLACE PACKAGE pkg_emp AS
FUNCTION get_annual_sal(p_empno NUMBER) RETURN NUMBER;
PROCEDURE raise_sal(p_empno NUMBER, p_pct NUMBER);
END pkg_emp;
-- 主體(實現細節)
CREATE OR REPLACE PACKAGE BODY pkg_emp AS
FUNCTION get_annual_sal(p_empno NUMBER) RETURN NUMBER IS
v_sal emp.sal%TYPE;
BEGIN
SELECT sal INTO v_sal FROM emp WHERE empno = p_empno;
RETURN v_sal * 12;
END;
-- ...
END pkg_emp;
pkg_emp.get_annual_sal 避免名稱衝突。DBMS_OUTPUT、UTL_FILE、DBMS_SCHEDULER 皆是此模式的標準實踐。Oracle 提供三種集合型別,讓集合操作具備強型別、物件化特徵:
| 型別 | 特性 | 對應概念 | 典型用法 |
|---|---|---|---|
| 關聯陣列 | 稀疏、任意索引(負數/字串)、僅 PL/SQL 可用 | Map/Dictionary | 快取、查找表 |
| 巢狀表 | 可存資料庫、支援多集合運算(MULTISET UNION/INTERSECT/EXCEPT) | List/Set | 表欄位、批量綁定 |
| VARRAY | 固定長度、有序、儲存內嵌 | Array | 小型固定集合(如電話清單) |
| 場景 | 推薦風格 | 理由 |
|---|---|---|
| 大量資料集合運算(篩選、聚合、連結) | 面向集合 | SQL 引擎優化、平行執行、向量化處理 |
| 複雜業務流程、狀態機、多步驟驗證 | 面向物件 | 封裝邏輯、單元測試、減少 Context Switch |
| 批量資料載入/轉換 (ETL) | 集合 + 批量綁定 | FORALL、BULK COLLECT 減少 SQL/PL/SQL 切換 |
| 階層式/遞迴資料處理 | 混合 | SQL CONNECT BY/WITH RECURSIVE + PL/SQL 封裝 |
Oracle 的偉大在於不強迫你二選一。核心引擎是集合論與關聯代數的極致實踐,同時提供物件導向的語法糖與擴展機制,讓開發者能在「宣告式集合操作」與「命令式物件邏輯」間自由切換。真正的專家,是懂得在 SQL 層面用集合思維解決 80% 問題,在 PL/SQL 層面用物件思維管控剩餘 20% 複雜度的人。