Her er fire metoder, du kan bruge til at finde dublerede rækker i SQL Server.
Med "duplikerede rækker" mener jeg to eller flere rækker, der deler nøjagtig de samme værdier på tværs af alle kolonner.
Eksempeldata
Antag, at vi har en tabel med følgende 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, at de første to rækker er dubletter, ligesom de sidste tre rækker.
Valgmulighed 1
Vi kan bruge følgende forespørgsel til at returnere oplysninger om duplikerede rækker:
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 udvide SELECT
liste for at inkludere flere kolonner, hvis det kræves:
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 | +---------+-----------+-----------+---------+
Hvis tabellen har en unik identifikator, kan vi blot fjerne denne kolonne fra forespørgslen. For eksempel, hvis vi antager, at PetId
kolonne er faktisk en primær nøglekolonne, der indeholder et unikt ID, kunne vi køre følgende forespørgsel for at returnere alle rækker, der er dubletter, uden at tælle primærnøglekolonnen med:
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 | +-----------+-----------+---------+
Valgmulighed 2
Hvis vi kun vil have de faktiske duplikerede rækker returneret, kan vi tilføje 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 | +---------+-----------+-----------+---------+
Valgmulighed 3
En anden måde at gøre det på er at bruge ROW_NUMBER()
funktion med PARTITION BY
klausul for at nummerere outputtet af resultatsættet.
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
klausul deler resultatsættet produceret af FROM
klausul i partitioner, som funktionen anvendes på. Når vi angiver partitioner for resultatsættet, får hver partition nummereringen til at starte forfra (dvs. nummereringen starter ved 1 for den første række i hver partition).
Valgmulighed 4
Hvis vi kun ønsker, at overskydende rækker fra de matchende dubletter skal returneres, kan vi bruge ovenstående forespørgsel som et almindeligt tabeludtryk, som dette:
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 af fordelene ved at gøre dette er, at vi kan slette duplikerede rækker blot ved at skifte SELECT *
til DELETE
(på sidste linje).
Derfor kan vi bruge ovenstående kode til at se, hvilke rækker der vil blive slettet, og når vi så er overbeviste om, at vi skal slette de korrekte rækker, kan vi skifte den til en DELETE
erklæring for rent faktisk at slette dem.
Sådan:
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;