Oracle 9i引入MERGE語句,取代傳統SELECT...IF EXISTS UPDATE ELSE INSERT邏輯,提供原子性、高效能、無競態條件的資料同步能力。
MERGE [hint] INTO target_table [t_alias]
USING source_table|view|subquery [s_alias]
ON (join_condition)
WHEN MATCHED THEN
UPDATE SET col1 = val1, col2 = val2 ...
[WHERE update_condition] -- 10g+ 可選條件更新
[DELETE WHERE delete_condition] -- 10g+ 可選刪除
WHEN NOT MATCHED THEN
INSERT (col1, col2, ...) VALUES (val1, val2, ...)
[WHERE insert_condition]; -- 10g+ 可選條件插入
-- 1. 建立測試表
CREATE TABLE tj_test (id NUMBER, name VARCHAR2(20), age NUMBER);
INSERT INTO tj_test VALUES (1, 'jan', 23);
INSERT INTO tj_test VALUES (2, 'kk', 22);
INSERT INTO tj_test VALUES (3, 'joe', 27);
-- 2. 來源表(僅結構)
CREATE TABLE tj_test1 AS SELECT * FROM tj_test WHERE 1=0;
INSERT INTO tj_test1 VALUES (1, 'jkl', 23); -- 同ID不同name
-- 3. MERGE同步:ID匹配更新name/age,否則插入
MERGE INTO tj_test1 t1
USING tj_test t
ON (t1.id = t.id)
WHEN MATCHED THEN
UPDATE SET t1.name = t.name, t1.age = t.age
WHEN NOT MATCHED THEN
INSERT (id, name, age) VALUES (t.id, t.name, t.age);
-- 4. 結果驗證
SELECT * FROM tj_test1 ORDER BY id;
-- 1 jan 23 (更新: jkl → jan)
-- 2 kk 22 (插入)
-- 3 joe 27 (插入)
| 場景 | 關鍵語法 | 範例 |
|---|---|---|
| 條件更新 | WHEN MATCHED THEN UPDATE ... WHERE t1.status != 'LOCKED' | 避免覆蓋鎖定記錄 |
| 條件插入 | WHEN NOT MATCHED THEN INSERT ... WHERE t.created > SYSDATE-30 | 僅同步近期資料 |
| 刪除同步 | WHEN MATCHED THEN UPDATE ... DELETE WHERE t1.flag = 'DEL' | 目標表標記刪除同步移除 |
| 單筆資料UPSERT | USING (SELECT :id id, :name name FROM DUAL) s | 應用層單筆寫入 |
| 多表關聯來源 | USING (SELECT ... FROM a JOIN b ON ...) s | 複雜ETL轉換 |
WHERE id BETWEEN ...或使用PARALLEL DMLALTER SESSION ENABLE PARALLEL DML; MERGE /*+ PARALLEL(t1 4) */ ...BEFORE/AFTER INSERT/UPDATE,注意業務邏輯遞歸LOG ERRORS子句記錄失敗行至錯誤表ORA-30926: unable to get a stable set of rows — 來源表連接鍵必須唯一ON (NVL(t1.id,-1) = NVL(t.id,-1)) 處理NULL匹配