Här är fyra metoder du kan använda för att hitta dubbletter av rader i SQL Server.
Med "dubbletter av rader" menar jag två eller flera rader som delar exakt samma värden i alla kolumner.
Exempeldata
Anta att vi har en tabell med följande data:
SELECT * FROM Pets;
Resultat:
+---------+-----------+-----------+ | PetId | PetName | PetType | |---------+-----------+-----------| | 1 | Wag | Dog | | 1 | Wag | Dog | | 2 | Scratch | Cat | | 3 | Tweet | Bird | | 4 | Bark | Dog | | 4 | Bark | Dog | | 4 | Bark | Dog | +---------+-----------+-----------+
Vi kan se att de två första raderna är dubbletter, liksom de tre sista raderna.
Alternativ 1
Vi kan använda följande fråga för att returnera information om dubbletter av rader:
SELECT
DISTINCT PetId,
COUNT(*) AS "Count"
FROM Pets
GROUP BY PetId
ORDER BY PetId;
Resultat:
+---------+---------+ | PetId | Count | |---------+---------| | 1 | 2 | | 2 | 1 | | 3 | 1 | | 4 | 3 | +---------+---------+
Vi kan utöka SELECT
lista för att inkludera fler kolumner om det behövs:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY PetId;
Resultat:
+---------+-----------+-----------+---------+ | PetId | PetName | PetType | Count | |---------+-----------+-----------+---------| | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+---------+
Om tabellen har en unik identifierare kan vi helt enkelt ta bort den kolumnen från frågan. Till exempel, om vi antar att PetId
kolumnen är faktiskt en primärnyckelkolumn som innehåller ett unikt ID, vi skulle kunna köra följande fråga för att returnera alla rader som är dubbletter, utan att räkna med primärnyckelkolumnen:
SELECT
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetName,
PetType
ORDER BY PetName;
Resultat:
+-----------+-----------+---------+ | PetName | PetType | Count | |-----------+-----------+---------| | Bark | Dog | 3 | | Scratch | Cat | 1 | | Tweet | Bird | 1 | | Wag | Dog | 2 | +-----------+-----------+---------+
Alternativ 2
Om vi bara vill att de faktiska dubblettraderna ska returneras kan vi lägga till HAVING
klausul:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
HAVING COUNT(*) > 1
ORDER BY PetId;
Resultat:
+---------+-----------+-----------+---------+ | PetId | PetName | PetType | Count | |---------+-----------+-----------+---------| | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+---------+
Alternativ 3
Ett annat sätt att göra det är att använda ROW_NUMBER()
funktion med PARTITION BY
sats för att numrera resultatet av resultatuppsättningen.
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets;
Resultat:
+---------+-----------+-----------+--------------+ | PetId | PetName | PetType | Row_Number | |---------+-----------+-----------+--------------| | 1 | Wag | Dog | 1 | | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 1 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+--------------+
PARTITION BY
satsen delar resultatuppsättningen som produceras av FROM
sats i partitioner som funktionen tillämpas på. När vi anger partitioner för resultatuppsättningen, gör varje partition att numreringen börjar om igen (dvs. numreringen börjar på 1 för den första raden i varje partition).
Alternativ 4
Om vi bara vill att överskottsrader från de matchande dubbletterna ska returneras, kan vi använda ovanstående fråga som ett vanligt tabelluttryck, så här:
WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets
)
SELECT * FROM CTE WHERE Row_Number <> 1;
Resultat:
+---------+-----------+-----------+--------------+ | PetId | PetName | PetType | Row_Number | |---------+-----------+-----------+--------------| | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+--------------+
En av fördelarna med att göra detta är att vi kan ta bort dubbletter av rader helt enkelt genom att byta SELECT *
till DELETE
(på sista raden).
Därför kan vi använda ovanstående kod för att se vilka rader som kommer att raderas, och när vi sedan är övertygade om att vi ska ta bort rätt rader kan vi byta den till en DELETE
uttalande för att faktiskt ta bort dem.
Så här:
WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets
)
DELETE FROM CTE WHERE Row_Number <> 1;