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

3 Möglichkeiten zum Löschen doppelter Zeilen in SQL Server unter Ignorieren des Primärschlüssels

In den folgenden Beispielen wird T-SQL verwendet, um doppelte Zeilen in SQL Server zu löschen, während der Primärschlüssel oder die eindeutige Bezeichnerspalte ignoriert werden.

Genauer gesagt löschen die Beispiele doppelte Zeilen, behalten aber eine bei. Bei zwei identischen Zeilen wird also eine gelöscht und die andere bleibt bestehen. Dies wird oft als „Deduplizierung“ der Tabelle, „Deduplizierung“ der Tabelle usw. bezeichnet.

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, ebenso wie die letzten drei Zeilen.

Möglichkeit 1

Lassen Sie uns zunächst den folgenden Code ausführen, um zu prüfen, welche Zeilen dedupliziert werden:

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            |
+---------+-------------+------------+--------------+

Wir haben die ROW_NUMBER() verwendet Funktion mit dem PARTITION BY -Klausel, um unsere eigene Zeilennummer zu erstellen, die sich erhöht, wenn Duplikate gefunden werden, und zurückgesetzt wird, wenn ein Nicht-Duplikat gefunden wird. Eine Zahl größer als 1 zeigt an, dass es sich um ein Duplikat handelt, und daher geben wir nur Zeilen zurück, die eine Zahl größer als 1 haben.

Wir können sehen, dass drei Zeilen gelöscht werden, wenn wir diese Tabelle deduplizieren.

Lassen Sie uns nun die Tabelle deduplizieren:

WITH cte AS 
    (
        SELECT 
            *,
            ROW_NUMBER() OVER ( 
                PARTITION BY FirstName, LastName 
                ORDER BY FirstName, LastName
                ) AS Row_Number
        FROM Dogs
    )
DELETE FROM cte WHERE Row_Number <> 1;

Ergebnis:

(3 rows affected)

Wie erwartet wurden drei Zeilen gelöscht.

Diese Abfrage ist fast identisch mit der vorherigen. Wir haben lediglich SELECT * geändert in der letzten Zeile zu DELETE .

Jetzt wählen wir alle Zeilen aus der Tabelle aus, um zu überprüfen, ob die richtigen Zeilen gelöscht wurden:

SELECT * FROM Dogs;

Ergebnis:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
+---------+-------------+------------+

Wir können sehen, dass jeder Hund jetzt nur einmal in der Tabelle vorkommt.

Option 2

Angenommen, die Tabelle wurde nach dem vorherigen Beispiel wiederhergestellt, hier ist eine andere Möglichkeit, nach Duplikaten zu suchen:

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    |
+---------+-------------+------------+

In diesem Fall haben wir von EXCEPT Gebrauch gemacht Operator zusammen mit dem MIN() Funktion. Wir könnten MIN() ersetzen mit MAX() je nachdem, welche Zeilen gelöscht werden sollen.

Um die Zeilen zu löschen, können wir einfach SELECT * ersetzen mit DELETE :

DELETE FROM Dogs 
WHERE DogId IN (
    SELECT DogId FROM Dogs 
    EXCEPT SELECT MIN(DogId) FROM Dogs 
    GROUP BY FirstName, LastName
    );

Ergebnis:

(3 rows affected)

Und prüfen Sie, was übrig ist:

SELECT * FROM Dogs;

Ergebnis:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
+---------+-------------+------------+

Möglichkeit 3

Eine andere Möglichkeit besteht darin, die Tabelle mit sich selbst zu verbinden und auf diese Weise nach Duplikaten zu suchen.

Unter der Annahme, dass die Tabelle nach dem vorherigen Beispiel wiederhergestellt wurde, ist hier unsere dritte Option zum Auswählen von Duplikaten:

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    |
+---------+-------------+------------+---------+-------------+------------+

Dieses Ergebnis ist nicht ganz so klar wie das im vorherigen Beispiel, aber wir können trotzdem sehen, welche Zeilen Duplikate sind.

Jetzt können wir diese Abfrage so ändern, dass wir doppelte Zeilen löschen:

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    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:

(3 rows affected)

Wieder wurden drei Zeilen gelöscht.

Sehen wir uns die Tabelle noch einmal an:

SELECT * FROM Dogs;

Ergebnis:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 2       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 7       | Wag         | Johnson    |
+---------+-------------+------------+

Sie werden vielleicht bemerken, dass dieses Mal die anderen Zeilen gelöscht wurden. Mit anderen Worten, wir haben jetzt DogId s 2, 3, 4 und 7, während wir in den vorherigen Beispielen bei 1, 3, 4 und 5 geblieben sind.

Wir können dieses Beispiel leicht ändern, um dieselben Zeilen wie in den vorherigen Beispielen zu löschen. Dazu können wir den MIN() verwenden Funktion anstelle von MAX() Funktion:

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    FROM Dogs d1, Dogs d2 
    WHERE d1.FirstName = d2.FirstName 
    AND d1.LastName = d2.LastName 
    AND d1.DogId <> d2.DogId 
    AND d1.DogId=( 
        SELECT MIN(DogId) 
        FROM Dogs d3 
        WHERE d3.FirstName = d1.FirstName 
        AND d3.LastName = d1.LastName
    )
);