首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

SQL Server 刪除重複記錄八大經典方案:從 NOT IN 到 ROW_NUMBER、CTE、臨時表全覆蓋

     編輯:MySQL 資料庫相關知識

場景定義

表 YourTable(id PK, name, value),保留 name+value 唯一組合的最小/最大 id,刪除其餘重複行。

方案對比表

方案核心語法適用場景效能備註
1. NOT IN 子查詢DELETE FROM t WHERE id NOT IN (SELECT MAX(id) FROM t GROUP BY name, value)小表、簡單去重NOT IN 遇 NULL 失效,大表慢
2. LEFT JOIN 保留最小 idDELETE a FROM t a LEFT JOIN (SELECT MIN(id) id FROM t GROUP BY name,value) b ON a.id=b.id WHERE b.id IS NULL中小表JOIN 比子查詢穩定
3. ROW_NUMBER() 窗口函數 (SQL 2005+)WITH cte AS (SELECT *, ROW_NUMBER() OVER(PARTITION BY name,value ORDER BY id) rn FROM t) DELETE FROM cte WHERE rn > 1大表、標準寫法單掃描、可並行、推薦首選
4. 臨時表重建SELECT DISTINCT * INTO #tmp FROM t; TRUNCATE TABLE t; INSERT INTO t SELECT * FROM #tmp全表重複、無 PK鎖表久、需重建索引/權限
5. 游標循環刪除DECLARE cur CURSOR FOR SELECT key, cnt FROM t GROUP BY key HAVING cnt>1 ... WHILE @@FETCH_STATUS=0 DELETE TOP(cnt-1) FROM t WHERE key=@key極舊版本無窗口函數效能極差、不推薦
6. IDENTITY 臨時表法SELECT IDENTITY(int,1,1) autoID,* INTO #tmp FROM t; SELECT MIN(autoID) INTO #tmp2 FROM #tmp GROUP BY name,value; SELECT * FROM #tmp WHERE autoID IN (SELECT autoID FROM #tmp2)保留第一行、需顯示結果兩次掃描、中等效能
7. Oracle ROWID 法 (異構參考)DELETE FROM t WHERE rowid NOT IN (SELECT MAX(rowid) FROM t GROUP BY cols)Oracle 專用物理地址定位、極快
8. MERGE 語句 (SQL 2008+)MERGE t USING (SELECT MIN(id) id, name, value FROM t GROUP BY name,value) s ON t.id=s.id WHEN NOT MATCHED BY SOURCE THEN DELETE同步/去重一體化單語句、可輸出動作日誌

生產環境推薦決策樹

  1. SQL Server 2005+ 且大表 → 方案 3 (ROW_NUMBER)
  2. 需審計刪除明細 → 方案 8 (MERGE ... OUTPUT $action, deleted.*)
  3. 無主鍵、全表重複 → 方案 4 (臨時表重建) 並同步重建索引
  4. 極小表/一次性清理 → 方案 1/2 皆可

預防重複根治

  • 加 UNIQUE INDEX (name, value) 從源頭阻擋
  • ETL 層做去重再入庫
  • 業務主鍵設計避免無意義自增列
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved