ORA-01452: cannot CREATE UNIQUE INDEX; duplicate keys found
嘗試對 code_ref 表建立唯一索引時發現重複鍵值。必須先識別並清除重複資料才能建立索引。本文介紹三種定位重複列的方法。
Oracle 每列擁有唯一 ROWID,利用 MAX(ROWID) 或 MIN(ROWID) 保留一筆、刪除其餘:
DELETE FROM code_ref a
WHERE ROWID < (SELECT MAX(ROWID)
FROM code_ref b
WHERE b.key_col1 = a.key_col1
AND b.key_col2 = a.key_col2
...);
優點:直觀、效能好、適用大多數場景。
SELECT key_col1, key_col2, COUNT(*) FROM code_ref GROUP BY key_col1, key_col2 HAVING COUNT(*) > 1;
先查出重複鍵值組合,再針對性刪除。適合先分析重複分布再決定清理策略。
@$ORACLE_HOME/rdbms/admin/utlexcpt.sql 建立 EXCEPTIONS 表(NT: ORACLE_HOME\Ora81\rdbms\admin,Unix: $ORACLE_HOME/rdbms/admin)ALTER TABLE code_ref ADD CONSTRAINT uk_code_ref UNIQUE (key_col1, key_col2) EXCEPTIONS INTO EXCEPTIONS;
ORA-02299,此時 EXCEPTIONS 表記錄違規列的 ROW_IDSELECT c.* FROM code_ref c, EXCEPTIONS e WHERE c.ROWID = e.ROW_ID AND e.CONSTRAINT = 'UK_CODE_REF';
| 方法 | 適用場景 | 優點 | 缺點 |
|---|---|---|---|
| ROWID 自關聯 | 單表清理、已知鍵欄位 | 單條 SQL 完成、效能最佳 | 需明確列出所有鍵欄位 |
| GROUP BY/HAVING | 分析重複分布、多鍵組合 | 集合操作直觀、易於驗證 | 需兩步驟(查詢→刪除) |
| EXCEPTIONS INTO | 約束驗證失敗、需記錄違規細節 | 原生約束機制、自動記錄 ROWID | 需預建 EXCEPTIONS 表、步驟較繁 |
TRUNCATE 原表再 INSERT /*+ APPEND */ 回寫DBMS_REDEFINITION 線上重定義表結構同時清理重複資料是資料品質的毒瘤,選對方法、分批處理、驗證結果,讓唯一約束順利建立,為資料完整性築牢防線。