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