複合類型 (Composite Types) 讓 PL/SQL 處理多值結構成為可能。本文系統整理三大集合類型——關聯陣列、巢狀表、VARRAY 的定義語法、特性差異、操作方法、適用場景,並提供完整可執行範例代碼。
| 特性 | 關聯陣列 | 巢狀表 | VARRAY |
|---|---|---|---|
| 定義語法 | TYPE t IS TABLE OF type INDEX BY PLS_INTEGER/VARCHAR2; | TYPE t IS TABLE OF type; | TYPE t IS VARRAY(n) OF type; |
| 索引類型 | PLS_INTEGER / VARCHAR2 | 正整數 (1 起) | 正整數 (1 起) |
| 大小限制 | 無上限 (記憶體允許) | 無上限 | 固定上限 n (MAX 2^31-1) |
| 稀疏性 | 支援 (可跳號) | 支援 (DELETE 後) | 不支援 (稠密) |
| 可存資料庫欄位 | 否 | 是 | 是 |
| 初始化 | 宣告即可用 | 需建構函數初始化 | 需建構函數初始化 |
| 擴展方法 | 直接指派新索引 | EXTEND | EXTEND |
| 典型用途 | 快取、查找表、稀疏矩陣 | 資料庫欄位、大量資料處理 | 有序小集合、固定上限場景 |
DECLARE
-- 定義:索引由 emp.ename 型別決定
TYPE emp_aa_type IS TABLE OF emp%ROWTYPE INDEX BY VARCHAR2(10);
v_emp_aa emp_aa_type;
v_idx VARCHAR2(10);
BEGIN
-- 填充:直接指派索引
FOR r IN (SELECT * FROM emp) LOOP
v_emp_aa(r.ename) := r;
END LOOP;
-- 遍歷:FIRST/NEXT 迴圈
v_idx := v_emp_aa.FIRST;
WHILE v_idx IS NOT NULL LOOP
DBMS_OUTPUT.PUT_LINE(v_emp_aa(v_idx).ename || ' - ' || v_emp_aa(v_idx).sal);
v_idx := v_emp_aa.NEXT(v_idx);
END LOOP;
-- 方法:COUNT, EXISTS, DELETE
DBMS_OUTPUT.PUT_LINE('總筆數: ' || v_emp_aa.COUNT);
IF v_emp_aa.EXISTS('KING') THEN
DBMS_OUTPUT.PUT_LINE('KING 存在');
END IF;
v_emp_aa.DELETE('KING'); -- 刪除單一元素
END;
DECLARE
TYPE str_nt_type IS TABLE OF VARCHAR2(20);
v_nt str_nt_type := str_nt_type('AA', 'BB'); -- 必須初始化
BEGIN
-- 擴展
v_nt.EXTEND(3); -- 增加 3 個 NULL 元素
v_nt(3) := 'CC'; -- 指派第 3 個
v_nt(4) := 'DD';
v_nt(5) := 'EE';
-- 遍歷
FOR i IN v_nt.FIRST .. v_nt.LAST LOOP
IF v_nt.EXISTS(i) THEN
DBMS_OUTPUT.PUT_LINE(i || ':' || v_nt(i));
END IF;
END LOOP;
-- 刪除中間元素 → 變稀疏
v_nt.DELETE(3);
DBMS_OUTPUT.PUT_LINE('COUNT=' || v_nt.COUNT || ' LAST=' || v_nt.LAST); -- COUNT=4 LAST=5
-- 可存入資料庫
-- CREATE TABLE nt_store (id NUMBER, data str_nt_type) NESTED TABLE data STORE AS nt_data_tab;
END;
DECLARE
TYPE ename_varray_type IS VARRAY(100) OF emp.ename%TYPE;
v_va ename_varray_type := ename_varray_type(); -- 初始化空陣列
v_cnt PLS_INTEGER := 0;
BEGIN
v_va.EXTEND(100); -- 一次擴展至上限
FOR r IN (SELECT ename FROM emp) LOOP
v_cnt := v_cnt + 1;
v_va(v_cnt) := r.ename;
EXIT WHEN v_cnt = 100; -- 達上限停止
END LOOP;
FOR i IN 1 .. v_va.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(v_va(i));
END LOOP;
-- VARRAY 不支援 DELETE 单一元素,只能 TRIM 尾部
v_va.TRIM(10); -- 移除最後 10 個
END;
| 方法 | 關聯陣列 | 巢狀表 | VARRAY | 說明 |
|---|---|---|---|---|
| COUNT | ✓ | ✓ | ✓ | 元素個數 |
| FIRST / LAST | ✓ | ✓ | ✓ | 首/尾索引 |
| NEXT / PRIOR | ✓ | ✓ | ✓ | 下一個/上一個索引 |
| EXISTS(n) | ✓ | ✓ | ✓ | 索引 n 是否存在 |
| EXTEND(n) | ✗ | ✓ | ✓ | 擴展 n 個 NULL 元素 |
| TRIM(n) | ✗ | ✓ | ✓ | 移除尾部 n 個元素 |
| DELETE(n) | ✓ | ✓ | ✗ | 刪除索引 n (巢狀表變稀疏) |
| DELETE | ✓ | ✓ | ✗ | 刪除所有元素 |
IF 需存入資料庫欄位:
IF 需固定上限且有序:
選 VARRAY
ELSE:
選巢狀表
ELSE: -- 純記憶體操作
IF 索引需為字串 OR 高度稀疏:
選關聯陣列
ELSE IF 固定上限:
選 VARRAY
ELSE:
選巢狀表 (功能最完整)
BULK COLLECT LIMIT 1000 分批處理,避免 PGA 爆漲NOCOPY 編譯器提示精通三大集合類型的定義語法、初始化差異、稀疏/稠密特性、持久化能力邊界,能讓 PL/SQL 開發者在記憶體資料結構設計、大量資料處理、資料庫物件映射三大場景中做出最優選擇。