Oto siedem sposobów zwracania zduplikowanych wierszy w PostgreSQL, gdy te wiersze mają klucz podstawowy lub inną kolumnę unikatowego identyfikatora.
Oznacza to, że zduplikowane wiersze mają dokładnie te same wartości we wszystkich kolumnach z wyjątkiem ich kolumny klucza podstawowego/unikalnego identyfikatora.
Przykładowe dane
W naszych przykładach użyjemy następujących danych:
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
Pierwsze dwa wiersze są duplikatami (z wyjątkiem DogId
kolumna, która jest kluczem podstawowym tabeli i zawiera unikatową wartość we wszystkich wierszach). Ostatnie trzy wiersze również są duplikatami (z wyjątkiem DogId
kolumna).
Kolumna klucza podstawowego zapewnia, że nie ma zduplikowanych wierszy, co jest dobrą praktyką w systemach RDBMS, ponieważ klucze podstawowe pomagają wymusić integralność danych. Ale ponieważ klucze podstawowe zapobiegają duplikowaniu wierszy, mogą one potencjalnie zakłócać naszą zdolność do znajdowania duplikatów.
W naszej tabeli powyżej kolumna klucza podstawowego jest liczbą rosnącą, a jej wartość nie ma znaczenia i nie jest istotna. Dlatego musimy zignorować ten wiersz, jeśli chcemy znaleźć duplikaty w innych kolumnach.
Opcja 1
Możemy użyć SQL GROUP BY
klauzula, aby pogrupować kolumny według ich znaczących kolumn, a następnie użyj COUNT()
funkcja zwracająca liczbę identycznych wierszy:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Wynik:
firstname | lastname | count -----------+----------+------- Ruff | Robinson | 1 Wag | Johnson | 3 Woof | Jones | 1 Bark | Smith | 2
Tutaj wykluczyliśmy kolumnę klucza podstawowego, pomijając ją w naszym zapytaniu.
Wynik mówi nam, że istnieją trzy wiersze zawierające Wag Johnson i dwa wiersze zawierające Bark Smith. Są to duplikaty (lub trzy egzemplarze w przypadku Wag Johnson). Pozostałe dwa wiersze nie mają żadnych duplikatów.
Opcja 2
Możemy wykluczyć nieduplikaty z danych wyjściowych za pomocą HAVING
klauzula:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Wynik:
firstname | lastname | count -----------+----------+------- Wag | Johnson | 3 Bark | Smith | 2
Opcja 3
Oto przykład sprawdzania duplikatów w połączonych kolumnach. W tym przypadku używamy CONCAT()
do łączenia naszych dwóch kolumn użyj funkcji DISTINCT
słowa kluczowego, aby uzyskać różne wartości, a następnie użyj COUNT()
funkcja zwracająca liczbę:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Wynik:
dogname | count ---------------+------- Wag Johnson | 3 Ruff Robinson | 1 Woof Jones | 1 Bark Smith | 2
Opcja 4
Alternatywnie możemy użyć ROW_NUMBER()
funkcja okna:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Wynik:
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
Korzystanie z PARTITION
klauzula powoduje dodanie nowej kolumny z numerem wiersza, który zwiększa się za każdym razem, gdy pojawia się duplikat, ale resetuje się ponownie, gdy istnieje unikalny wiersz.
W tym przypadku nie grupujemy wyników, co oznacza, że możemy zobaczyć każdy zduplikowany wiersz, w tym jego kolumnę z unikalnym identyfikatorem.
Opcja 5
Możemy również użyć poprzedniego przykładu jako wspólnego wyrażenia tabelowego w większym zapytaniu:
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
Wyklucza to nieduplikaty z danych wyjściowych i wyklucza jeden wiersz każdego duplikatu z danych wyjściowych. Innymi słowy, pokazuje tylko nadmiarowe wiersze z duplikatów. Te wiersze są głównymi kandydatami do usunięcia w operacji usuwania duplikatów.
Opcja 6
Oto bardziej zwięzły sposób uzyskania tego samego wyniku, co w poprzednim przykładzie:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Wynik:
dogid | firstname | lastname -------+-----------+---------- 6 | Wag | Johnson 2 | Bark | Smith 7 | Wag | Johnson
Jedną z różnic między tym przykładem a poprzednim jest to, że ten przykład nie wymaga generowania własnego oddzielnego numeru wiersza.
Opcja 7
Oto kolejna opcja zwracania zduplikowanych wierszy w Postgresie:
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