Här är sju alternativ för att hitta dubbletter av rader i SQL Server, när dessa rader har en primärnyckel eller annan unik identifierarkolumn.
Tabellen innehåller med andra ord två eller flera rader som delar exakt samma värden i alla kolumner förutom dess unika identifierarkolumn.
Exempeldata
Anta att vi har en tabell med följande data:
SELECT * FROM Dogs;
Resultat:
+---------+-------------+------------+ | DogId | FirstName | LastName | |---------+-------------+------------| | 1 | Bark | Smith | | 2 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +---------+-------------+------------+
Vi kan se att de två första raderna är dubbletter (förutom DogId
kolumn, som innehåller ett unikt värde över alla rader och kan användas som tabellens primära nyckelkolumn). Vi kan också se att de tre sista raderna är dubbletter (förutom DogId
kolumn).
Den unika ID-kolumnen säkerställer att det inte finns några dubbletter av rader, vilket normalt är en mycket önskvärd egenskap i RDBMS. Men i det här fallet har det potential att störa vår förmåga att hitta dubbletter. Per definition säkerställer den unika ID-kolumnen att det inte finns några dubbletter. Lyckligtvis kan vi lösa detta problem ganska enkelt, vilket följande exempel visar.
Alternativ 1
Förmodligen är det enklaste/enklaste sättet att göra det med en enkel fråga som använder GROUP BY
klausul:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Resultat:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Woof | Jones | 1 | | Ruff | Robinson | 1 | | Bark | Smith | 2 | +-------------+------------+---------+
Vi kunde utesluta kolumnen primärnyckel/unika ID genom att utelämna den från vår fråga.
Resultatet berättar att det finns tre rader som innehåller Wag Johnson och två rader som innehåller Bark Smith. Dessa är dubbletter (eller triplikat i fallet med Wag Johnson).
Alternativ 2
Vi kan utesluta icke-duplikat från resultatet genom att inkludera HAVING
klausul i vår fråga:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Resultat:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Bark | Smith | 2 | +-------------+------------+---------+
Alternativ 3
Vi kan också kontrollera om det finns dubbletter på sammanlänkade kolumner. Till exempel kan vi använda CONCAT()
funktion för att sammanfoga våra två kolumner:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Resultat:
+---------------+---------+ | DogName | Count | |---------------+---------| | Bark Smith | 2 | | Ruff Robinson | 1 | | Wag Johnson | 3 | | Woof Jones | 1 | +---------------+---------+
Alternativ 4
Vi kan använda ROW_NUMBER()
funktion med PARTITION BY
sats för att skapa en ny kolumn med ett radnummer som ökar varje gång det finns en dubblett, men återställs igen när det finns en unik rad:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Resultat:
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 1 | Bark | Smith | 1 | | 2 | Bark | Smith | 2 | | 4 | Ruff | Robinson | 1 | | 5 | Wag | Johnson | 1 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | | 3 | Woof | Jones | 1 | +---------+-------------+------------+--------------+
En fördel med den här metoden är att vi kan se varje dubblettrad, tillsammans med dess unika identifierarkolumn, på grund av det faktum att vi inte grupperar resultaten.
Alternativ 5
Vi kan också använda föregående exempel som ett vanligt tabelluttryck i en större fråga:
WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs
)
SELECT * FROM cte WHERE Row_Number <> 1;
Resultat:
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 2 | Bark | Smith | 2 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +---------+-------------+------------+--------------+
Det här alternativet utesluter icke-dubbletter från utdata.
Det exkluderar också exakt en rad av varje dubblett från utdata. Detta öppnar dörren för oss att vrida den sista DELETE
att de-dupera tabellen samtidigt som du behåller en av varje dubblett.
Alternativ 6
Här är ett mer kortfattat sätt att få samma utdata som föregående exempel:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Resultat:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Det här exemplet kräver inte att vi genererar vårt eget separata radnummer.
Alternativ 7
Och slutligen, här är en lite mer invecklad teknik för att returnera dubbletter av rader:
SELECT *
FROM Dogs d1, Dogs d2
WHERE d1.FirstName = d2.FirstName
AND d1.LastName = d2.LastName
AND d1.DogId <> d2.DogId
AND d1.DogId = (
SELECT MAX(DogId)
FROM Dogs d3
WHERE d3.FirstName = d1.FirstName
AND d3.LastName = d1.LastName
);
Resultat:
+---------+-------------+------------+---------+-------------+------------+ | DogId | FirstName | LastName | DogId | FirstName | LastName | |---------+-------------+------------+---------+-------------+------------| | 2 | Bark | Smith | 1 | Bark | Smith | | 7 | Wag | Johnson | 5 | Wag | Johnson | | 7 | Wag | Johnson | 6 | Wag | Johnson | +---------+-------------+------------+---------+-------------+------------+
Även resultatet ser mer invecklat ut, men hey, det visar oss fortfarande dubbletterna!