Det enklaste sättet är med en CTE (common table expression). Jag använder den här metoden när jag har rådata att importera; det första jag gör för att sanera det är att försäkra mig om att det inte finns några dubbletter --- att jag har något slags unikt handtag på varje rad.
Sammanfattning:
WITH numbered AS (
SELECT ROW_NUMBER() OVER(PARTITION BY [dupe-column-list] ORDER BY [dupe-column-list]) AS _dupe_num FROM [table-name] WHERE 1=1
)
DELETE FROM numbered WHERE _dupe_num > 1;
Delen "dupe-kolumn-lista" är där du listar alla inblandade kolumner där du önskar att värden var unika. ORDER BY är där du bestämmer, inom en uppsättning dubbletter, vilken rad som "vinner" och vilken som ska raderas. (WHERE 1=1 är bara en personlig vana.)
Anledningen till att det fungerar är att SQL Server har en intern, unik referens till varje källrad som är vald i CTE. Så när DELETE exekveras vet den exakt vilken rad som ska raderas, oavsett vad du lägger i din CTE:s vallista. (Om du är nervös kan du ändra "DELETE" till "SELECT *", men eftersom du har dubbletter av rader kommer det inte att hjälpa; om du kunde identifiera varje rad unikt skulle du inte läsa detta .)
Exempel:
CREATE TABLE ##_dupes (col1 int, col2 int, col3 varchar(50));
INSERT INTO ##_dupes
VALUES (1, 1, 'one,one')
, (2, 2, 'two,two')
, (3, 3, 'three,three')
, (1, 1, 'one,one')
, (1, 2, 'one,two')
, (3, 3, 'three,three')
, (1, 1, 'one,one')
, (1, 2, '1,2');
Av de 8 raderna har du 5 inblandade med dubbla problem; 3 rader måste tas bort. Du kan se problemen med detta:
SELECT col1
, col2
, col3
, COUNT(1) AS _total
FROM ##_dupes
WHERE 1=1
GROUP BY col1, col2, col3
HAVING COUNT(1) > 1
ORDER BY _total DESC;
Kör nu följande fråga för att ta bort dubbletterna och lämna 1 rad från varje uppsättning dubbletter.
WITH numbered AS (
SELECT ROW_NUMBER() OVER(PARTITION BY col1, col2, col3 ORDER BY col1, col2, col3) AS _dupe_num FROM ##_dupes WHERE 1=1
)
DELETE FROM numbered WHERE _dupe_num > 1;
Du har nu 5 rader, varav ingen är duplicerad.