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

SQL Server 刪除重複資料完全指南:游標法、DISTINCT 法與 ROW_NUMBER 進階技巧

     編輯:MySQL 資料庫相關知識

資料庫因程式邏輯缺失或匯入流程疏漏,常產生重複資料,導致主鍵/唯一索引無法建立、統計報表失真。本文提供三種刪除重複資料的方案,從傳統游標迴圈到現代視窗函數,適用不同版本與場景。

重複資料類型辨析

  • 完全重複:所有欄位值皆相同。
  • 關鍵欄位重複:如 Name、Email 等業務鍵重複,其他欄位可能不同;通常保留第一筆或最新一筆。

方法一:游標逐筆刪除(舊版相容,效能較差)

DECLARE @max INT, @id INT;
DECLARE cur_rows CURSOR LOCAL FOR
  SELECT 主鍵欄位, COUNT(*) 
  FROM 表名 
  GROUP BY 主鍵欄位 
  HAVING COUNT(*) > 1;

OPEN cur_rows;
FETCH NEXT FROM cur_rows INTO @id, @max;

WHILE @@FETCH_STATUS = 0
BEGIN
  SET @max = @max - 1;          -- 保留 1 筆
  SET ROWCOUNT @max;            -- 限制影響列數
  DELETE FROM 表名 WHERE 主鍵欄位 = @id;
  FETCH NEXT FROM cur_rows INTO @id, @max;
END

CLOSE cur_rows;
DEALLOCATE cur_rows;
SET ROWCOUNT 0;                 -- 還原無限制
缺點: 逐筆處理、鎖定時間長、不支援平行處理,大量資料慎用。

方法二:DISTINCT 暫存表法(完全重複資料)

-- 1. 建立無重複暫存表
SELECT DISTINCT * INTO #Tmp FROM tableName;

-- 2. 刪除原表並重建
DROP TABLE tableName;
SELECT * INTO tableName FROM #Tmp;
DROP TABLE #Tmp;
根治建議: 事後請於關鍵欄位加上 UNIQUE INDEX 或 PRIMARY KEY,從源頭防止重複寫入。

方法三:ROW_NUMBER() 保留首筆(關鍵欄位重複,SQL 2005+)

-- 1. 加入流水號
SELECT IDENTITY(INT,1,1) AS autoID, * INTO #Tmp FROM tableName;

-- 2. 依業務鍵分組取最小 autoID(即第一筆)
SELECT MIN(autoID) AS autoID INTO #Tmp2 
FROM #Tmp 
GROUP BY Name, Address;  -- 業務鍵欄位

-- 3. 取得去重後結果集
SELECT * FROM #Tmp WHERE autoID IN (SELECT autoID FROM #Tmp2);

-- 實際刪除時可用:
-- DELETE t FROM tableName t
-- WHERE t.autoID NOT IN (SELECT autoID FROM #Tmp2);

現代寫法:CTE + ROW_NUMBER() 單陳述式刪除(SQL 2005+ 推薦)

WITH CTE AS (
  SELECT *,
         ROW_NUMBER() OVER (PARTITION BY Name, Address ORDER BY ID) AS rn
  FROM tableName
)
DELETE FROM CTE WHERE rn > 1;

效能與選型建議

場景推薦方法備註
小量資料、舊版 SQL 2000游標法簡單但慢
完全重複、可離線維護DISTINCT 暫存表速度快,需重建索引/權限
關鍵欄位重複、線上業務CTE + ROW_NUMBER單一陳述式、鎖定時間短、可加 WHERE 限制範圍

建立完善的資料品質檢核機制(ETL 階段去重、資料庫約束、應用層冪等設計),才是杜絕重複資料的根本之道。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved