萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

SQL Server 刪除重複資料三大經典方法:游標法、臨時表法、ROW_NUMBER 法

資料庫重複資料清理三大經典模式,按資料量、版本、複雜度選型。

方法一:游標逐組刪除 (SQL 2000 相容、大資料量分批)

DECLARE @max INT, @id INT;
DECLARE cur CURSOR LOCAL FOR
    SELECT 主鍵, COUNT(*) FROM 表名 GROUP BY 主鍵 HAVING COUNT(*) > 1;
OPEN cur;
FETCH NEXT FROM cur INTO @id, @max;
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @max = @max - 1;          -- 保留 1 筆
    SET ROWCOUNT @max;            -- 限制刪除筆數
    DELETE FROM 表名 WHERE 主鍵 = @id;
    FETCH NEXT FROM cur INTO @id, @max;
END
CLOSE cur; DEALLOCATE cur;
SET ROWCOUNT 0;  -- 重置全域限制

優點:分批刪除避免長鎖表、不需額外空間。
缺點:游標慢、SET ROWCOUNT 影響後續語句、SQL 2012+ 棄用 ROWCOUNT。

方法二:臨時表去重 (完全重複列、保留 1 筆)

-- 1. 建立無重複臨時表
SELECT DISTINCT * INTO #Tmp FROM TableName;

-- 2. 清空原表
TRUNCATE TABLE TableName;  -- 或 DELETE (若有觸發器)

-- 3. 寫回
INSERT INTO TableName SELECT * FROM #Tmp;
DROP TABLE #Tmp;

適用:完全重複 (所有欄位相同)、中小表。
根治:事後**加上唯一索引/主鍵**防止再犯。

方法三:關鍵欄位重複、保留首筆 (自增 ID 法)

-- 假設重複判斷欄位為 Name, Address
SELECT IDENTITY(INT,1,1) AS autoID, * INTO #Tmp FROM TableName;
SELECT MIN(autoID) AS autoID INTO #Tmp2 FROM #Tmp GROUP BY Name, Address;
SELECT * FROM #Tmp WHERE autoID IN (SELECT autoID FROM #Tmp2);
-- 最後 SELECT 即為去重結果,實際刪除需配合 MERGE 或 JOIN DELETE

現代最佳寫法: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、可讀性高、效能最優、支援任意保留策略 (最早/最新/最大 ID)。

選型建議

場景推薦方法版本需求
完全重複、小表DISTINCT + 臨時表All
關鍵欄位重複、大表、需分批游標 + ROWCOUNT2000+
關鍵欄位重複、追求效能/可維護ROW_NUMBER() CTE2005+
生產環境標準化ROW_NUMBER() + 交易控制2005+

防重複根本對策

  1. 表設計階段加 UNIQUE INDEX / PRIMARY KEY
  2. 應用層冪等性設計 (唯一業務鍵)
  3. ETL 階段去重入庫
copyright © 萬盛學電腦網 all rights reserved