Vilket är det bästa sättet att ta bort dubbla rader från en ganska stor SQL Server
tabell (dvs. 300 000+ rader)?
Raderna kommer naturligtvis inte att vara perfekta dubbletter eftersom identitetsfältet RowID
finns.
MyTable
RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null
Om du antar att det inte finns några nollor, så gör du en gruppering efter de unika kolumnerna och väljer den lägsta (eller högsta) RowId-numret som den rad som ska behållas. Sedan raderar du allt som inte har ett row id:
DELETE FROM MyTable
LEFT OUTER JOIN (
SELECT MIN(RowId) as RowId, Col1, Col2, Col3
FROM MyTable
GROUP BY Col1, Col2, Col3
) as KeepRows ON
MyTable.RowId = KeepRows.RowId
WHERE
KeepRows.RowId IS NULL
Om du har en GUID istället för ett heltal kan du ersätta
MIN(RowId)
med
CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))
Det finns en bra artikel om att ta bort dubbletter på Microsofts supportwebbplats. Den är ganska konservativ - du måste göra allt i separata steg - men den borde fungera bra för stora tabeller.
Jag har tidigare använt self-joins för att göra detta, även om det förmodligen skulle kunna förbättras med en HAVING-klausul:
DELETE dupes
FROM MyTable dupes, MyTable fullTable
WHERE dupes.dupField = fullTable.dupField
AND dupes.secondDupField = fullTable.secondDupField
AND dupes.uniqueField > fullTable.uniqueField
Här är en annan bra artikel om att ta bort dubbletter.
Den diskuterar varför det är svårt: "SQL bygger på relationsalgebra, och dubbletter kan inte förekomma i relationsalgebra, eftersom dubbletter inte är tillåtna i en uppsättning."
Lösningen med temp table och två mysql-exempel.
Kommer ni i framtiden att förhindra detta på databasnivå eller ur ett applikationsperspektiv? Jag skulle föreslå databasnivå eftersom din databas bör vara ansvarig för att upprätthålla referentiell integritet, utvecklare kommer bara att orsaka problem ;)