Hier zijn zeven opties voor het vinden van dubbele rijen in SQL Server, wanneer die rijen een primaire sleutel of een andere unieke id-kolom hebben.
Met andere woorden, de tabel bevat twee of meer rijen die exact dezelfde waarden delen in alle kolommen, behalve de unieke id-kolom.
Voorbeeldgegevens
Stel dat we een tabel hebben met de volgende gegevens:
SELECT * FROM Dogs;
Resultaat:
+---------+-------------+------------+ | DogId | FirstName | LastName | |---------+-------------+------------| | 1 | Bark | Smith | | 2 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +---------+-------------+------------+
We kunnen zien dat de eerste twee rijen duplicaten zijn (behalve de DogId
kolom, die een unieke waarde voor alle rijen bevat en kan worden gebruikt als de primaire sleutelkolom van de tabel). We kunnen ook zien dat de laatste drie rijen duplicaten zijn (behalve de DogId
kolom).
De unieke ID-kolom zorgt ervoor dat er geen dubbele rijen zijn, wat normaal gesproken een zeer wenselijke eigenschap is in RDBMS'en. In dit geval heeft het echter de potentie om ons vermogen om duplicaten te vinden te verstoren. De unieke ID-kolom zorgt er per definitie voor dat er geen duplicaten zijn. Gelukkig kunnen we dit probleem vrij eenvoudig oplossen, zoals de volgende voorbeelden laten zien.
Optie 1
Waarschijnlijk de gemakkelijkste/eenvoudigste manier om dit te doen, is met een eenvoudige query die de GROUP BY
gebruikt clausule:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Resultaat:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Woof | Jones | 1 | | Ruff | Robinson | 1 | | Bark | Smith | 2 | +-------------+------------+---------+
We hebben de kolom primaire sleutel/unieke ID kunnen uitsluiten door deze uit onze zoekopdracht weg te laten.
Het resultaat vertelt ons dat er drie rijen zijn met Wag Johnson en twee rijen met Bark Smith. Dit zijn duplicaten (of drievoud in het geval van Wag Johnson).
Optie 2
We kunnen niet-duplicaten uitsluiten van het resultaat door de HAVING
. op te nemen clausule in onze vraag:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Resultaat:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Bark | Smith | 2 | +-------------+------------+---------+
Optie 3
We kunnen ook controleren op duplicaten op aaneengeschakelde kolommen. We kunnen bijvoorbeeld de CONCAT()
. gebruiken functie om onze twee kolommen samen te voegen:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Resultaat:
+---------------+---------+ | DogName | Count | |---------------+---------| | Bark Smith | 2 | | Ruff Robinson | 1 | | Wag Johnson | 3 | | Woof Jones | 1 | +---------------+---------+
Optie 4
We kunnen de ROW_NUMBER()
. gebruiken functie met de PARTITION BY
clausule om een nieuwe kolom te maken met een rijnummer dat wordt verhoogd telkens wanneer er een duplicaat is, maar opnieuw wordt hersteld wanneer er een unieke rij is:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Resultaat:
+---------+-------------+------------+--------------+ | 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 | +---------+-------------+------------+--------------+
Een voordeel van deze methode is dat we elke dubbele rij kunnen zien, samen met de unieke ID-kolom, omdat we de resultaten niet groeperen.
Optie 5
We kunnen het vorige voorbeeld ook gebruiken als een algemene tabeluitdrukking in een grotere query:
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;
Resultaat:
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 2 | Bark | Smith | 2 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +---------+-------------+------------+--------------+
Deze optie sluit niet-duplicaten uit van de uitvoer.
Het sluit ook precies één rij van elk duplicaat uit van de uitvoer. Dit opent de deur voor ons om de laatste SELECT *
. te draaien in een DELETE
om de tabel te ontdubbelen terwijl u een van elk duplicaat behoudt.
Optie 6
Hier is een beknoptere manier om dezelfde uitvoer te krijgen als in het vorige voorbeeld:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Resultaat:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Voor dit voorbeeld is het niet nodig om ons eigen aparte rijnummer te genereren.
Optie 7
En tot slot, hier is een iets ingewikkelder techniek om dubbele rijen te retourneren:
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
);
Resultaat:
+---------+-------------+------------+---------+-------------+------------+ | DogId | FirstName | LastName | DogId | FirstName | LastName | |---------+-------------+------------+---------+-------------+------------| | 2 | Bark | Smith | 1 | Bark | Smith | | 7 | Wag | Johnson | 5 | Wag | Johnson | | 7 | Wag | Johnson | 6 | Wag | Johnson | +---------+-------------+------------+---------+-------------+------------+
Zelfs het resultaat ziet er ingewikkelder uit, maar hey, het laat ons nog steeds de duplicaten zien!