建立唯一索引失敗 ORA-02299,提示存在重複鍵值。需先識別並清理重複列,再建立約束。
SELECT a.*
FROM table_name a
JOIN (SELECT key_col, MIN(rowid) AS keep_rid
FROM table_name
GROUP BY key_col
HAVING COUNT(*) > 1) b
ON a.key_col = b.key_col
AND a.rowid > b.keep_rid; -- 保留 MIN(rowid),其餘為重複
SELECT key_col, COUNT(*) AS dup_cnt
FROM table_name
GROUP BY key_col
HAVING COUNT(*) > 1;
-- 1. 建立 EXCEPTIONS 表 (腳本 $ORACLE_HOME/rdbms/admin/utlexcpt.sql)
@?/rdbms/admin/utlexcpt.sql
-- 2. 嘗試啟用約束,違規列導入 EXCEPTIONS
ALTER TABLE table_name ADD CONSTRAINT uk_key UNIQUE (key_col)
EXCEPTIONS INTO exceptions;
-- 3. 查詢重複列
SELECT t.*
FROM table_name t
JOIN exceptions e ON t.rowid = e.row_id
WHERE e.constraint = 'UK_KEY';
-- 保留每組第一筆 (依 ROWID)
DELETE FROM table_name
WHERE rowid NOT IN (
SELECT MIN(rowid) FROM table_name GROUP BY key_col
);
BEGIN
LOOP
DELETE FROM table_name
WHERE rowid IN (
SELECT rowid FROM (
SELECT rowid, ROW_NUMBER() OVER (PARTITION BY key_col ORDER BY rowid) rn
FROM table_name
) WHERE rn > 1
AND ROWNUM <= 50000
);
EXIT WHEN SQL%ROWCOUNT = 0;
COMMIT;
END LOOP;
END;
/
-- 最後建立唯一索引/約束
| 需求 | 推薦方法 |
|---|---|
| 快速統計重複鍵值分佈 | GROUP BY / HAVING |
| 需審核完整重複列內容 | 自關聯 ROWID |
| 建立約束前一站式檢查 | EXCEPTIONS INTO |
| 生產環境大表清理 | 分批 DELETE + ROW_NUMBER() |