UPDATE student a
SET (a.name, a.dq) = (
SELECT b.bname, b.bdq
FROM newstudent b
WHERE b.bid = a.id
AND a.dq = 10
)
WHERE EXISTS (
SELECT 1
FROM newstudent b
WHERE b.bid = a.id
AND a.dq = 10
);
| 子句 | 作用 | 關鍵點 |
|---|---|---|
SET (col1, col2) = (SELECT ...) | 多欄位同時賦值 | 子查詢必須返回唯一行,否則報 ORA-01427 |
WHERE EXISTS (...) | 僅更新有匹配行的目標行 | 避免無匹配時置 NULL;EXISTS 比 IN 效率高(半連接) |
關聯條件 b.bid = a.id | 表間連接鍵 | 確保 newstudent.bid 有唯一索引/主鍵 |
過濾條件 a.dq = 10 | 業務篩選 | 同時出現在子查詢與 EXISTS 中,保證一致性 |
MERGE INTO student a
USING (
SELECT bid, bname, bdq
FROM newstudent
WHERE bid IN (SELECT id FROM student WHERE dq = 10)
) b
ON (a.id = b.bid)
WHEN MATCHED THEN
UPDATE SET a.name = b.bname, a.dq = b.bdq
WHERE a.dq = 10; -- 可選:進一步限制更新範圍
MERGE 優勢:單掃描源表、支援 INSERT/UPDATE/DELETE 組合、並行 DML 友好、語義更清晰。
student(id) PK、newstudent(bid) PK/UK、student(dq) 索引(若選擇性高)。DBMS_STATS.GATHER_TABLE_STATS 確保優化器準確估算基數。ALTER SESSION ENABLE PARALLEL DML; UPDATE /*+ PARALLEL(a,4) */ ...(EE)。WHERE id BETWEEN ... AND ... 循環更新,中間 COMMIT,控制 UNDO/REDO 與鎖持有時間。
| 錯誤 | 原因 | 修正 |
|---|---|---|
| ORA-01427: single-row subquery returns more than one row | 源表關聯鍵非唯一 | 加 DISTINCT、聚合或唯一約束;或用 ROW_NUMBER()=1 取單行 |
| 無匹配行時目標列變 NULL | 缺少 WHERE EXISTS | 必須加 WHERE EXISTS 或 MERGE WHEN MATCHED |
| 死鎖 | 多會話反序更新同組行 | 應用層統一按 PK 排序更新;或 SELECT ... FOR UPDATE NOWAIT |
Oracle 多表關聯更新多欄位的標準姿勢是:SET (c1,c2) = (SELECT ...) + WHERE EXISTS,或更現代的 MERGE。關鍵在於保證源數據唯一性、加上精確過濾條件、配合索引與統計信息獲得最優執行計劃。大批量場景務必分批提交、考慮並行 DML,並在維護窗口內操作。