假設 EMPLOYEE 表包含 EMP_ID(主鍵)、EMP_NAME,需以姓名判斷重複,保留最小 ID 的那一筆。
-- 僅顯示重複的姓名與次數 select emp_name, count(*) from employee group by emp_name having count(*) > 1;
select t1.*
from employee t1
where t1.emp_name in (
select t2.emp_name
from employee t2
group by t2.emp_name
having count(*) > 1
)
and t1.emp_id not in (
select min(t3.emp_id)
from employee t3
group by t3.emp_name
having count(*) > 1
);
delete from employee t1
where t1.emp_name in (
select t2.emp_name
from employee t2
group by t2.emp_name
having count(*) > 1
)
and t1.emp_id not in (
select min(t3.emp_id)
from employee t3
group by t3.emp_name
having count(*) > 1
);
delete from employee
where rowid not in (
select min(rowid)
from employee
group by emp_name
);
delete from employee
where emp_id in (
select emp_id from (
select emp_id,
row_number() over (partition by emp_name order by emp_id) rn
from employee
)
where rn > 1
);
delete from employee
where rowid not in (
select min(rowid)
from employee
group by emp_name, id_card
);
-- 建立備份表 create table employee_bak as select * from employee; -- 或匯出關鍵資料 -- 刪除後立即驗證 select emp_name, count(*) from employee group by emp_name having count(*) > 1;
| 方法 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| NOT IN 子查詢 | 語法直觀 | 大量資料效能差,NULL 值陷阱 | 小表、臨時清理 |
| ROWID | 最快,無需掃描索引 | ROWID 可能因搬移而變動 | 大表、一次性清理 |
| ROW_NUMBER() | 彈性高,可指定保留邏輯 | 需全表掃描排序 | 複雜去重邏輯、保留最新/最舊 |