重複資料分兩類:完全重複(所有欄位相同)與關鍵欄位重複(如 Name 相同但其他欄位不同)。本文提供三種刪除策略,依資料量與需求選用。
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;
原理:對每組重複值設定 ROWCOUNT 限制刪除筆數,保留第一筆。
SELECT DISTINCT * INTO #Tmp FROM 表名; DROP TABLE 表名; SELECT * INTO 表名 FROM #Tmp; DROP TABLE #Tmp;
或直接 SELECT DISTINCT * FROM 表名 取得無重複結果集。
根因對策:加上唯一索引/主鍵防止再次產生重複。
-- 產生流水號 SELECT IDENTITY(INT,1,1) AS autoID, * INTO #Tmp FROM 表名; -- 取每組關鍵欄位的最小 autoID SELECT MIN(autoID) AS autoID INTO #Tmp2 FROM #Tmp GROUP BY Name, Address; -- 保留目標筆 SELECT * FROM #Tmp WHERE autoID IN (SELECT autoID FROM #Tmp2);
實務上可改用 ROW_NUMBER() OVER (PARTITION BY 關鍵欄位 ORDER BY 排序欄位) 單一查詢完成,效能更佳。
選型建議:
• 完全重複 + 小表 → 方法二
• 關鍵欄位重複 + 需保留特定邏輯首筆 → 方法三(現代寫法用 CTE + ROW_NUMBER)
• 巨量資料、不想記錄交易日誌 → 分批刪除或TRUNCATE重建