需求:CODE 欄位有重複值,依 CODE 分組加流水號(如 201402_1、201402_2)。傳統寫法需建臨時表或 MERGE,Oracle 支援 UPDATE ... SET col = (WITH ... SELECT ...) 直接完成。
DROP TABLE test PURGE; CREATE TABLE test (id NUMBER, code VARCHAR2(20), name VARCHAR2(20)); INSERT INTO test VALUES (1,'201401','aaa'); INSERT INTO test VALUES (2,'201402','bbb'); INSERT INTO test VALUES (3,'201402','ccc'); INSERT INTO test VALUES (4,'201403','ddd'); INSERT INTO test VALUES (5,'201403','eee'); INSERT INTO test VALUES (6,'201403','fff'); COMMIT;
SELECT t.id,
code || '_' || ROW_NUMBER() OVER (PARTITION BY code ORDER BY id) AS new_code
FROM test t;
-- 結果:
-- 1 201401_1
-- 2 201402_1
-- 3 201402_2
-- 4 201403_1
-- 5 201403_2
-- 6 201403_3
UPDATE test t SET t.code = ( SELECT code || '_' || ROW_NUMBER() OVER (PARTITION BY code ORDER BY id) FROM test t1 WHERE t1.id = t.id ); -- 結果錯誤:所有 201402 變 201402_1,201403 變 201403_1 -- 原因:標量子查詢每行獨立執行,窗口函數無法跨行分區
UPDATE test b
SET b.code = (
WITH t AS (
SELECT id, code || '_' || ROW_NUMBER() OVER (PARTITION BY code ORDER BY id) AS new_code
FROM test
)
SELECT a.new_code FROM t a WHERE a.id = b.id
);
-- 結果正確:
-- 1 201401_1 aaa
-- 2 201402_1 bbb
-- 3 201402_2 ccc
-- 4 201403_1 ddd
-- 5 201403_2 eee
-- 6 201403_3 fff
WITH 子查詢(CTE)在 UPDATE 陳述式層級執行**一次**,產生完整結果集WHERE a.id = b.id 逐行映射,窗口函數正確分區計算MERGE 搭配 WITH 更直觀WHERE ROWNUM <= 10000 循環,避免 Undo 爆滿FLASHBACK TABLE test TO BEFORE DROP