創建唯一索引報錯:ORA-01452: cannot create unique index; duplicate keys found。需先定位並清理重復行。
-- 保留 ROWID 最大 (最新) 的行,刪除其餘
DELETE FROM code_ref a
WHERE rowid < (SELECT MAX(rowid)
FROM code_ref b
WHERE b.pk_col1 = a.pk_col1
AND b.pk_col2 = a.pk_col2); -- 唯一鍵列組合
原理:同一鍵值的行 ROWID 不同,保留最大值即保留最後插入的一行。
-- 1. 定位重復鍵值
SELECT pk_col1, pk_col2, COUNT(*)
FROM code_ref
GROUP BY pk_col1, pk_col2
HAVING COUNT(*) > 1;
-- 2. 刪除重復 (保留 MIN rowid)
DELETE FROM code_ref
WHERE rowid NOT IN (
SELECT MIN(rowid)
FROM code_ref
GROUP BY pk_col1, pk_col2
);
-- 1. 創建 EXCEPTIONS 表 (腳本 $ORACLE_HOME/rdbms/admin/utlexcpt.sql)
@?/rdbms/admin/utlexcpt.sql -- 創建 EXCEPTIONS 表
-- 2. 嘗試創建索引,將違規行導入 EXCEPTIONS
ALTER TABLE code_ref ADD CONSTRAINT pk_code_ref PRIMARY KEY (pk_col1, pk_col2)
EXCEPTIONS INTO EXCEPTIONS;
-- 報錯 ORA-02299: cannot validate - duplicate keys found
-- 但 EXCEPTIONS 表已填入 ROWID
-- 3. 關聯刪除
DELETE FROM code_ref
WHERE rowid IN (SELECT row_id FROM EXCEPTIONS);
-- 或保留一行:需配合 ROWID 比較
| 維度 | ROWID 自關聯 | GROUP BY HAVING | EXCEPTIONS INTO |
|---|---|---|---|
| 適用版本 | 所有版本 | 所有版本 | 8i+ |
| 性能 (大表) | 全表自關聯,較慢 | 單掃描 + 排序,較快 | 索引構建過程中完成,無額外掃描 |
| 保留策略控制 | 靈活 (MAX/MIN/條件) | 靈活 | 需後續手工處理 |
| 推薦場景 | 小表、臨時清理 | 中大表、標準化腳本 | 創建約束時同步清理 |
-- 確認無重復
SELECT pk_col1, pk_col2, COUNT(*)
FROM code_ref
GROUP BY pk_col1, pk_col2
HAVING COUNT(*) > 1;
-- 無行返回 = 清理完成
-- 正常創建唯一索引
CREATE UNIQUE INDEX idx_code_ref_pk ON code_ref(pk_col1, pk_col2);