Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

3 sposoby na usunięcie zduplikowanych wierszy w SQL Server, ignorując klucz podstawowy

Poniższe przykłady używają T-SQL do usuwania zduplikowanych wierszy w SQL Server, ignorując klucz podstawowy lub kolumnę unikatowego identyfikatora.

Dokładniej, przykłady usuwają zduplikowane wiersze, ale zachowują jeden. Tak więc, biorąc pod uwagę dwa identyczne wiersze, jeden jest usuwany, a drugi pozostaje. Jest to często określane jako „deduplikacja” tabeli, „deduplikacja” tabeli itp.

Przykładowe dane

Załóżmy, że mamy tabelę z następującymi danymi:

SELECT * FROM Dogs;

Wynik:

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

Widać, że pierwsze dwa wiersze są duplikatami, podobnie jak ostatnie trzy wiersze.

Opcja 1

Najpierw uruchommy następujący kod, aby sprawdzić, które wiersze zostaną usunięte:

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;

Wynik:

+---------+-------------+------------+--------------+
| DogId   | FirstName   | LastName   | Row_Number   |
|---------+-------------+------------+--------------|
| 2       | Bark        | Smith      | 2            |
| 6       | Wag         | Johnson    | 2            |
| 7       | Wag         | Johnson    | 3            |
+---------+-------------+------------+--------------+

Użyliśmy ROW_NUMBER() funkcja z PARTITION BY klauzula, aby utworzyć własny numer wiersza, który zwiększa się, gdy zostaną znalezione jakiekolwiek duplikaty, i resetuje się, gdy zostanie znaleziony nieduplikat. Liczba większa niż 1 wskazuje, że jest to duplikat, dlatego zwracamy tylko wiersze, które mają liczbę większą niż 1.

Widzimy, że po usunięciu duplikatu tej tabeli zostaną usunięte trzy wiersze.

Teraz odduplikujmy tabelę:

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;

Wynik:

(3 rows affected)

Zgodnie z oczekiwaniami usunięto trzy wiersze.

To zapytanie jest prawie identyczne z poprzednim. Zmieniliśmy tylko SELECT * w ostatniej linii do DELETE .

Teraz wybierzmy wszystkie wiersze z tabeli, aby sprawdzić, czy usunięto prawidłowe wiersze:

SELECT * FROM Dogs;

Wynik:

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

Widzimy, że każdy pies pojawia się teraz w tabeli tylko raz.

Opcja 2

Zakładając, że tabela została przywrócona po poprzednim przykładzie, oto inny sposób sprawdzania duplikatów:

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

Wynik:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 2       | Bark        | Smith      |
| 6       | Wag         | Johnson    |
| 7       | Wag         | Johnson    |
+---------+-------------+------------+

W tym przypadku skorzystaliśmy z EXCEPT operator wraz z MIN() funkcjonować. Moglibyśmy zastąpić MIN() z MAX() w zależności od tego, które wiersze chcemy usunąć.

Aby usunąć wiersze, możemy po prostu zastąpić SELECT * z DELETE :

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

Wynik:

(3 rows affected)

I sprawdź, co pozostało:

SELECT * FROM Dogs;

Wynik:

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

Opcja 3

Innym sposobem na to jest samodzielne dołączenie do stołu i sprawdzenie w ten sposób duplikatów.

Zakładając, że tabela została przywrócona po poprzednim przykładzie, oto nasza trzecia opcja wyboru duplikatów:

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
);

Wynik:

+---------+-------------+------------+---------+-------------+------------+
| DogId   | FirstName   | LastName   | DogId   | FirstName   | LastName   |
|---------+-------------+------------+---------+-------------+------------|
| 2       | Bark        | Smith      | 1       | Bark        | Smith      |
| 7       | Wag         | Johnson    | 5       | Wag         | Johnson    |
| 7       | Wag         | Johnson    | 6       | Wag         | Johnson    |
+---------+-------------+------------+---------+-------------+------------+

Ten wynik nie jest tak wyraźny jak w poprzednim przykładzie, ale nadal możemy zobaczyć, które wiersze są duplikatami.

Teraz możemy zmodyfikować to zapytanie, aby usunąć zduplikowane wiersze:

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
    )
);

Wynik:

(3 rows affected)

Po raz kolejny trzy wiersze zostały usunięte.

Sprawdźmy ponownie tabelę:

SELECT * FROM Dogs;

Wynik:

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

Możesz zauważyć, że tym razem pozostałe wiersze zostały usunięte. Innymi słowy, mamy teraz DogId s 2, 3, 4 i 7, podczas gdy w poprzednich przykładach zostały nam 1, 3, 4 i 5.

Możemy łatwo zmienić ten przykład, aby usunąć te same wiersze, co w poprzednich przykładach. Aby to zrobić, możemy użyć MIN() funkcja zamiast MAX() funkcja:

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
    )
);

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wstawiaj zbiorczo pola o stałej szerokości

  2. Użyj TYPEPROPERTY(), aby zwrócić informacje o typie danych w SQL Server

  3. Jak opróżnić bufor PRINT w TSQL?

  4. Sprawdź, czy wyjście RPC jest włączone na połączonym serwerze

  5. Projekt bazy danych:Obliczanie salda konta