遇到表中存在完全一模一樣的重複行(無主鍵、無唯一約束),需刪除重複僅保留第一條。本文提供經典 SELECT INTO #Temp 去重方案,並說明 SELECT INTO 權限開啟方法。
-- 1. 將去重後數據導入臨時表
SELECT DISTINCT * INTO #TmpTable FROM SourceTable;
-- 2. 清空原表
DELETE FROM SourceTable;
-- 3. 將去重數據寫回原表
SELECT * INTO SourceTable FROM #TmpTable;
-- 4. 刪除臨時表
DROP TABLE #TmpTable;
SQL Server 默認關閉 SELECT INTO,執行上述腳本會報錯。兩種開啟方式:
EXEC sp_dboption 'DatabaseName', 'select into', 'true';
執行後立即生效,無需重啟。
若「首條」定義為按某字段排序第一條(如最早創建時間),而非物理存儲順序:
;WITH CTE AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3 ORDER BY CreateTime ASC) AS RN
FROM SourceTable
)
DELETE FROM SourceTable
WHERE EXISTS (
SELECT 1 FROM CTE
WHERE CTE.Col1 = SourceTable.Col1
AND CTE.Col2 = SourceTable.Col2
AND CTE.Col3 = SourceTable.Col3
AND CTE.RN > 1
);
PARTITION BY 列出構成「重複」判定的所有業務列。ORDER BY 定義保留哪一條(如最早/最新/ID 最小)。| 方案 | 適用數據量 | 鎖定行為 | 優點 | 缺點 |
|---|---|---|---|---|
| SELECT INTO #Temp | ≤ 100 萬行 | Sch-M 鎖(DDL),阻塞所有訪問 | 簡單、兼容老版本 | 大表鎖表久、需啟用選項 |
| ROW_NUMBER() CTE DELETE | 任意(配合批次) | 行級鎖(X),並發友好 | 無 DDL 鎖、可保留業務首條、現代語法 | 需 2005+、大表建議分批提交 |
| MERGE + WHEN NOT MATCHED | 大表增量去重 | 行級鎖 | 可同步源目標、支持 UPSERT | 語法複雜、需目標表有鍵 |