Oracle 9i 引入 MERGE,10g/11g 持續增強(支援 `DELETE` 子句、錯誤記錄、並行提示)。適用於數據倉儲 ETL、增量同步、緩存刷新等高頻 Upsert 場景。
MERGE [hint] INTO target_table [t_alias]
USING {source_table | view | subquery} [s_alias]
ON (join_condition)
WHEN MATCHED THEN
UPDATE SET col1 = expr1, col2 = expr2 [WHERE update_condition]
[DELETE WHERE delete_condition] -- 10g+ 新增
WHEN NOT MATCHED THEN
INSERT (col1, col2, ...) VALUES (expr1, expr2, ...)
[WHERE insert_condition]; -- 10g+ 新增
-- 目標表
CREATE TABLE tj_test1 (id NUMBER PRIMARY KEY, name VARCHAR2(20), age NUMBER);
INSERT INTO tj_test1 VALUES (1, 'jkl', 23);
-- 來源表
CREATE TABLE tj_test AS SELECT * FROM tj_test1 WHERE 1=0;
INSERT INTO tj_test VALUES (1, 'jan', 23);
INSERT INTO tj_test VALUES (2, 'kk', 22);
INSERT INTO tj_test VALUES (3, 'joe', 27);
-- MERGE:id 相同更新 name/age,不同則插入
MERGE INTO tj_test1 tgt
USING tj_test src
ON (tgt.id = src.id)
WHEN MATCHED THEN
UPDATE SET tgt.name = src.name, tgt.age = src.age
WHEN NOT MATCHED THEN
INSERT (id, name, age) VALUES (src.id, src.name, src.age);
-- 結果:id=1 name 從 jkl→jan,新增 id=2,3
MERGE INTO course c
USING (
SELECT course_name, period, course_hours
FROM course_updates
) cu
ON (c.course_name = cu.course_name AND c.period = cu.period)
WHEN MATCHED THEN
UPDATE SET c.course_hours = cu.course_hours
WHEN NOT MATCHED THEN
INSERT (course_name, period, course_hours)
VALUES (cu.course_name, cu.period, cu.course_hours);
MERGE INTO config tgt
USING (SELECT 'MAX_SESSIONS' key, '500' val FROM dual) src
ON (tgt.cfg_key = src.key)
WHEN MATCHED THEN UPDATE SET tgt.cfg_val = src.val
WHEN NOT MATCHED THEN INSERT (cfg_key, cfg_val) VALUES (src.key, src.val);
| 陷阱 | 現象 | 對策 |
|---|---|---|
| ON 條件非唯一 | ORA-30926: unable to get a stable set of rows | 確保目標表 ON 欄位唯一,或來源去重 |
| WHEN MATCHED UPDATE 觸發遞迴觸發器 | 無限遞迴/效能崩塌 | 觸發器中判斷 `IF UPDATING('col')` 限制範圍 |
| 大量 NOT MATCHED 導致 High Water Mark 飆升 | 插入後表空間未回收 | 定期 `ALTER TABLE ... SHRINK SPACE` 或分區表 |
| 並行 MERGE 產生死鎖 | ORA-00060 | 來源/目標表按相同順序加鎖,或降低 DOP |
`MERGE` 是 Oracle 實現 Upsert 的標準化、集合化利器。掌握其完整語法(含 `DELETE/WHERE` 子句)、索引設計原則、分批並行策略,能將 ETL 合併邏輯從「存儲過程+迴圈」重構為單一 SQL,提升可維護性與效能數個數量級。