Hier sind sieben Optionen zum Auffinden doppelter Zeilen in SQL Server, wenn diese Zeilen einen Primärschlüssel oder eine andere eindeutige Bezeichnerspalte haben.
Mit anderen Worten, die Tabelle enthält zwei oder mehr Zeilen, die in allen Spalten mit Ausnahme der eindeutigen Kennungsspalte genau dieselben Werte aufweisen.
Beispieldaten
Angenommen, wir haben eine Tabelle mit den folgenden Daten:
SELECT * FROM Dogs;
Ergebnis:
+---------+-------------+------------+ | DogId | FirstName | LastName | |---------+-------------+------------| | 1 | Bark | Smith | | 2 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +---------+-------------+------------+
Wir können sehen, dass die ersten beiden Zeilen Duplikate sind (mit Ausnahme der DogId
Spalte, die in allen Zeilen einen eindeutigen Wert enthält und als Primärschlüsselspalte der Tabelle verwendet werden könnte). Wir können auch sehen, dass die letzten drei Zeilen Duplikate sind (mit Ausnahme der DogId
Spalte).
Die eindeutige ID-Spalte stellt sicher, dass es keine doppelten Zeilen gibt, was normalerweise eine sehr wünschenswerte Eigenschaft in RDBMSs ist. In diesem Fall besteht jedoch das Potenzial, dass unsere Fähigkeit, Duplikate zu finden, beeinträchtigt wird. Per Definition stellt die eindeutige ID-Spalte sicher, dass es keine Duplikate gibt. Glücklicherweise können wir dieses Problem ganz einfach lösen, wie die folgenden Beispiele zeigen.
Option 1
Der wahrscheinlich einfachste Weg, dies zu tun, ist eine einfache Abfrage, die den GROUP BY
verwendet Klausel:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Ergebnis:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Woof | Jones | 1 | | Ruff | Robinson | 1 | | Bark | Smith | 2 | +-------------+------------+---------+
Wir konnten die Primärschlüssel/eindeutige ID-Spalte ausschließen, indem wir sie aus unserer Abfrage wegließen.
Das Ergebnis sagt uns, dass es drei Zeilen mit Wag Johnson und zwei Zeilen mit Bark Smith gibt. Dies sind Duplikate (oder Triplikate im Fall von Wag Johnson).
Option 2
Wir können Nicht-Duplikate aus dem Ergebnis ausschließen, indem wir den HAVING
einbeziehen Klausel in unserer Abfrage:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Ergebnis:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Bark | Smith | 2 | +-------------+------------+---------+
Option 3
Wir können auch nach Duplikaten in verketteten Spalten suchen. Zum Beispiel können wir den CONCAT()
verwenden Funktion zum Verketten unserer beiden Spalten:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Ergebnis:
+---------------+---------+ | DogName | Count | |---------------+---------| | Bark Smith | 2 | | Ruff Robinson | 1 | | Wag Johnson | 3 | | Woof Jones | 1 | +---------------+---------+
Option 4
Wir können die ROW_NUMBER()
verwenden Funktion mit dem PARTITION BY
-Klausel, um eine neue Spalte mit einer Zeilennummer zu erstellen, die jedes Mal erhöht wird, wenn es ein Duplikat gibt, aber wieder zurückgesetzt wird, wenn es eine eindeutige Zeile gibt:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Ergebnis:
+---------+-------------+------------+--------------+ | 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 | +---------+-------------+------------+--------------+
Ein Vorteil dieser Methode besteht darin, dass wir jede einzelne doppelte Zeile zusammen mit ihrer eindeutigen ID-Spalte sehen können, da wir die Ergebnisse nicht gruppieren.
Option 5
Wir können das vorherige Beispiel auch als allgemeinen Tabellenausdruck in einer größeren Abfrage verwenden:
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;
Ergebnis:
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 2 | Bark | Smith | 2 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +---------+-------------+------------+--------------+
Diese Option schließt Nicht-Duplikate von der Ausgabe aus.
Es schließt auch genau eine Zeile jedes Duplikats aus der Ausgabe aus. Dies öffnet uns die Tür, um das letzte SELECT *
zu drehen in ein DELETE
um die Tabelle zu deduplizieren, während eines von jedem Duplikat beibehalten wird.
Option 6
Hier ist ein prägnanterer Weg, um die gleiche Ausgabe wie im vorherigen Beispiel zu erhalten:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Ergebnis:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Für dieses Beispiel ist es nicht erforderlich, unsere eigene separate Zeilennummer zu generieren.
Option 7
Und schließlich ist hier eine etwas kompliziertere Technik, um doppelte Zeilen zurückzugeben:
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
);
Ergebnis:
+---------+-------------+------------+---------+-------------+------------+ | DogId | FirstName | LastName | DogId | FirstName | LastName | |---------+-------------+------------+---------+-------------+------------| | 2 | Bark | Smith | 1 | Bark | Smith | | 7 | Wag | Johnson | 5 | Wag | Johnson | | 7 | Wag | Johnson | 6 | Wag | Johnson | +---------+-------------+------------+---------+-------------+------------+
Sogar das Ergebnis sieht verworrener aus, aber hey, es zeigt uns immer noch die Duplikate!