Oto siedem sposobów zwracania zduplikowanych wierszy w MySQL, gdy te wiersze mają klucz podstawowy lub inną kolumnę unikatowego identyfikatora.
Przykładowe dane
W naszych przykładach użyjemy następujących danych:
DROP TABLE IF EXISTS Dogs;
CREATE TABLE Dogs (
DogId int PRIMARY KEY NOT NULL,
FirstName varchar(50),
LastName varchar(50)
);
INSERT INTO Dogs VALUES
(1, 'Bark', 'Smith'),
(2, 'Bark', 'Smith'),
(3, 'Woof', 'Jones'),
(4, 'Ruff', 'Robinson'),
(5, 'Wag', 'Johnson'),
(6, 'Wag', 'Johnson'),
(7, 'Wag', 'Johnson');
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 | +-------+-----------+----------+
Zduplikowane wiersze mają dokładnie te same wartości we wszystkich kolumnach z wyjątkiem ich kolumny klucza podstawowego/unikalnego identyfikatora.
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 zwykle jest dobrą rzeczą w systemach RDBMS. Jednak z definicji oznacza to, że nie ma duplikatów. W naszym przypadku 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 kolumnach, które są istotne.
Opcja 1
Naszą pierwszą opcją jest użycie 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 | +-----------+----------+-------+ | Bark | Smith | 2 | | Woof | Jones | 1 | | Ruff | Robinson | 1 | | Wag | Johnson | 3 | +-----------+----------+-------+
Udało nam się zignorować kolumnę klucza podstawowego, pomijając ją w naszym zapytaniu.
Wynik mówi nam, że istnieją dwa wiersze zawierające Bark Smith i trzy wiersze zawierające Wag Johnson. 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 | +-----------+----------+-------+ | Bark | Smith | 2 | | Wag | Johnson | 3 | +-----------+----------+-------+
Opcja 3
Możemy również sprawdzić duplikaty w połączonych kolumnach. Na przykład możemy użyć 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 | +---------------+-------+ | Bark Smith | 2 | | Woof Jones | 1 | | Ruff Robinson | 1 | | Wag Johnson | 3 | +---------------+-------+
Opcja 4
Alternatywnie możemy użyć ROW_NUMBER()
funkcja z PARTITION BY
klauzula:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS rn
FROM Dogs;
Wynik:
+-------+-----------+----------+----+ | DogId | FirstName | LastName | rn | +-------+-----------+----------+----+ | 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 | +-------+-----------+----------+----+
Tworzy to nową kolumnę z numerem wiersza, który zwiększa się za każdym razem, gdy pojawia się duplikat, ale resetuje się ponownie, gdy pojawia się unikalny wiersz
Ta technika zapewnia możliwą korzyść, ponieważ nie musimy grupować wyników. Oznacza to, że możemy zobaczyć każdy zduplikowany wiersz, w tym jego kolumnę z unikalnym identyfikatorem.
Opcja 5
Możemy 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 rn
FROM Dogs
)
SELECT * FROM cte WHERE rn <> 1;
Wynik:
+-------+-----------+----------+----+ | DogId | FirstName | LastName | rn | +-------+-----------+----------+----+ | 2 | Bark | Smith | 2 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +-------+-----------+----------+----+
Ta technika wyklucza z danych wyjściowych nieduplikaty i jeden wiersz każdego duplikatu z danych wyjściowych.
To zapytanie może służyć jako prekursor operacji usuwania duplikatów. Może nam pokazać, co zostanie usunięte, jeśli zdecydujemy się usunąć duplikaty. Aby usunąć duplikat tabeli, wystarczy zastąpić ostatni SELECT *
z DELETE
.
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
WHERE DogId NOT IN (SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName)
);
Wynik:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Ta technika nie wymaga od nas generowania oddzielnego numeru wiersza za pomocą ROW_NUMBER()
jak w poprzednim przykładzie.
Możemy również zastąpić SELECT *
z DELETE
aby usunąć duplikaty.
Opcja 7
I na koniec jeszcze jedna opcja zwracania 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 | +-------+-----------+----------+-------+-----------+----------+