Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

7 Möglichkeiten, doppelte Zeilen in SQL Server zu finden, während alle Primärschlüssel ignoriert werden

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!