Oracle 集合型別包含三種:Varrays (變長陣列)、Nested Tables (巢狀表)、Associative Arrays (關聯陣列/索引表)。巢狀表是無固定大小上限的有序集合,元素型別相同,可儲存於資料表欄位中,支援 SQL 操作 (SELECT/INSERT/UPDATE/DELETE),是實現「表中表」關係的強大工具。本文從型別建立、資料表定義、CRUD 操作完整示範。
CREATE OR REPLACE TYPE name_typ AS OBJECT (
first_name VARCHAR2(30),
second_name VARCHAR2(30),
short_name VARCHAR2(10)
);
/
-- Type created
CREATE OR REPLACE TYPE nested_table_name AS TABLE OF name_typ;
/
-- Type created
關鍵字: 使用 TABLE OF 而非 AS TABLE OF,後者會報 ORA-00928。
CREATE TABLE test_family (
family_id NUMBER(6) PRIMARY KEY,
members nested_table_name
)
NESTED TABLE members STORE AS nested_members;
/
-- Table created
NESTED TABLE members STORE AS nested_members:指定巢狀表資料的實體儲存段名稱 (存儲表),必須指定,否則報 ORA-22913。nested_members 為系統自動維護的獨立段,不可直接 DML,需透過父表操作。DESC nested_table_name;
-- NESTED_TABLE_NAME TABLE OF NAME_TYP
-- FIRST_NAME, SECOND_NAME, SHORT_NAME
DESC test_family;
-- FAMILY_ID NUMBER(6)
-- MEMBERS NESTED_TABLE_NAME
SET DESCRIBE DEPTH 2
DESC test_family;
-- 顯示巢狀表內屬性細節
SELECT * FROM user_nested_tables;
-- 查看所有巢狀表欄位對應的儲存表名稱
-- 家庭 1:兩位成員
INSERT INTO test_family VALUES (
1,
nested_table_name(
name_typ('張', '金花婆婆', '婆婆'),
name_typ('楊', '00', '楊帥帥')
)
);
-- 家庭 2:四位成員
INSERT INTO test_family VALUES (
2,
nested_table_name(
name_typ('曹', '妙妙草', '苗苗'),
name_typ('徐', '0', '海豹'),
name_typ('狄', '狄狄兔', '海洋一餅'),
name_typ('於', '00', '小魚')
)
);
-- 查詢整個家庭 (巢狀表以集合形式顯示)
SELECT * FROM test_family WHERE family_id = 1;
-- 展開巢狀表查詢 (使用 TABLE() 函數)
SELECT f.family_id, m.*
FROM test_family f, TABLE(f.members) m
WHERE f.family_id = 1;
-- 統計每個家庭成員數
SELECT family_id, CARDINALITY(members) AS member_cnt
FROM test_family;
-- 向家庭 1 新增一位成員
INSERT INTO TABLE(SELECT members FROM test_family WHERE family_id = 1)
VALUES (name_typ('蘇', '小可', '可可豆'));
-- 修改家庭 1 中暱稱 '可可豆' 的成員姓名
UPDATE TABLE(SELECT members FROM test_family WHERE family_id = 1) m
SET m = name_typ('莫', '小米', '可可豆')
WHERE m.short_name = '可可豆';
語法重點: TABLE(SELECT nested_col FROM parent_table WHERE ...) 將巢狀表轉為可 DML 的虛擬表。
-- 刪除家庭 1 中暱稱 '可可豆' 的成員
DELETE FROM TABLE(SELECT members FROM test_family WHERE family_id = 1) m
WHERE m.short_name = '可可豆';
-- 檢查家庭 1 最終成員
SELECT f.family_id, m.*
FROM test_family f, TABLE(f.members) m
WHERE f.family_id = 1;
-- 結果:張/金花婆婆/婆婆、楊/00/楊帥帥 (蘇/莫已被刪除/修改)
| 特性 | 巢狀表 | Varrays |
|---|---|---|
| 大小上限 | 無 (受限於表空間) | 建立時指定最大元素數 |
| 儲存方式 | 獨立儲存段 (Out-of-line) | 內嵌父表 (Inline,小於 4KB 時) |
| 索引支援 | 可建立索引於儲存表 | 不支援 |
| 稀疏性 | 支援 (可刪除中間元素) | 密集 (不可有空洞) |
| 適用場景 | 大量、不固定、需獨立查詢的子資料 | 少量、固定、常整體讀寫的屬性 |
-- 在儲存表上建立索引加速巢狀表查詢
CREATE INDEX idx_nested_short_name ON nested_members (short_name);
DECLARE
v_members nested_table_name := nested_table_name();
BEGIN
v_members.EXTEND(3);
v_members(1) := name_typ('A', 'B', 'C');
-- 可使用 FIRST, LAST, NEXT, PRIOR, EXISTS, COUNT, LIMIT, EXTEND, TRIM, DELETE 等集合方法
FOR i IN v_members.FIRST .. v_members.LAST LOOP
DBMS_OUTPUT.PUT_LINE(v_members(i).short_name);
END LOOP;
END;
/
FORALL + 集合變數減少 Context Switch。巢狀表是 Oracle 物件關聯特性的核心,善用可減少 JOIN 複雜度,但需權衡維護成本。建議先在開發環境完整測試資料量增長對效能的影響。