Oto cztery metody, których można użyć do znalezienia zduplikowanych wierszy w programie SQL Server.
Przez „zduplikowane wiersze” rozumiem dwa lub więcej wierszy, które mają dokładnie te same wartości we wszystkich kolumnach.
Przykładowe dane
Załóżmy, że mamy tabelę z następującymi danymi:
SELECT * FROM Pets;
Wynik:
+---------+-----------+-----------+ | PetId | PetName | PetType | |---------+-----------+-----------| | 1 | Wag | Dog | | 1 | Wag | Dog | | 2 | Scratch | Cat | | 3 | Tweet | Bird | | 4 | Bark | Dog | | 4 | Bark | Dog | | 4 | Bark | Dog | +---------+-----------+-----------+
Widzimy, że pierwsze dwa wiersze są duplikatami, podobnie jak ostatnie trzy wiersze.
Opcja 1
Możemy użyć następującego zapytania, aby zwrócić informacje o zduplikowanych wierszach:
SELECT
DISTINCT PetId,
COUNT(*) AS "Count"
FROM Pets
GROUP BY PetId
ORDER BY PetId;
Wynik:
+---------+---------+ | PetId | Count | |---------+---------| | 1 | 2 | | 2 | 1 | | 3 | 1 | | 4 | 3 | +---------+---------+
Możemy rozwinąć SELECT
lista zawierająca więcej kolumn, jeśli jest to wymagane:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY PetId;
Wynik:
+---------+-----------+-----------+---------+ | PetId | PetName | PetType | Count | |---------+-----------+-----------+---------| | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+---------+
Jeśli tabela ma unikalny identyfikator, możemy po prostu usunąć tę kolumnę z zapytania. Na przykład, jeśli założymy, że PetId
kolumna jest w rzeczywistości kolumną klucza podstawowego zawierającą unikalny identyfikator, moglibyśmy uruchomić następujące zapytanie, aby zwrócić wszystkie wiersze, które są duplikatami, nie licząc kolumny klucza podstawowego:
SELECT
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetName,
PetType
ORDER BY PetName;
Wynik:
+-----------+-----------+---------+ | PetName | PetType | Count | |-----------+-----------+---------| | Bark | Dog | 3 | | Scratch | Cat | 1 | | Tweet | Bird | 1 | | Wag | Dog | 2 | +-----------+-----------+---------+
Opcja 2
Jeśli chcemy zwrócić tylko rzeczywiste zduplikowane wiersze, możemy dodać HAVING
klauzula:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
HAVING COUNT(*) > 1
ORDER BY PetId;
Wynik:
+---------+-----------+-----------+---------+ | PetId | PetName | PetType | Count | |---------+-----------+-----------+---------| | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+---------+
Opcja 3
Innym sposobem na to jest użycie ROW_NUMBER()
funkcja z PARTITION BY
klauzula do numerowania danych wyjściowych zestawu wyników.
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets;
Wynik:
+---------+-----------+-----------+--------------+ | PetId | PetName | PetType | Row_Number | |---------+-----------+-----------+--------------| | 1 | Wag | Dog | 1 | | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 1 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+--------------+
PARTITION BY
klauzula dzieli zbiór wyników utworzony przez FROM
klauzuli na przegrody, do których funkcja jest stosowana. Kiedy określamy partycje dla zestawu wyników, każda partycja powoduje, że numeracja zaczyna się od nowa (tj. numeracja rozpocznie się od 1 dla pierwszego wiersza w każdej partycji).
Opcja 4
Jeśli chcemy, aby zwracane były tylko dodatkowe wiersze z pasujących duplikatów, możemy użyć powyższego zapytania jako wspólnego wyrażenia tabelowego, na przykład:
WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets
)
SELECT * FROM CTE WHERE Row_Number <> 1;
Wynik:
+---------+-----------+-----------+--------------+ | PetId | PetName | PetType | Row_Number | |---------+-----------+-----------+--------------| | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+--------------+
Jedną z korzyści płynących z tego jest to, że możemy usunąć zduplikowane wiersze po prostu przełączając SELECT *
do DELETE
(w ostatniej linii).
Dlatego możemy użyć powyższego kodu, aby zobaczyć, które wiersze zostaną usunięte, a następnie, gdy jesteśmy przekonani, że zamierzamy usunąć prawidłowe wiersze, możemy przełączyć go na DELETE
oświadczenie, aby faktycznie je usunąć.
Tak:
WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets
)
DELETE FROM CTE WHERE Row_Number <> 1;