Her er syv måder at returnere duplikerede rækker i MariaDB, når disse rækker har en primærnøgle eller anden unik identifikatorkolonne.
Derfor deler de duplikerede rækker nøjagtig de samme værdier på tværs af alle kolonner undtagen deres unikke identifikatorkolonne.
Eksempel på data
Vi bruger følgende data til vores eksempler:
SELECT * FROM Dogs;
Resultat:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 1 | Bark | Smith | | 2 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
De første to rækker er dubletter (undtagen DogId
kolonne, som er tabellens primære nøgle og indeholder en unik værdi på tværs af alle rækker). De sidste tre rækker er også dubletter (bortset fra DogId
kolonne).
Den primære nøglekolonne sikrer, at der ikke er nogen duplikerede rækker, hvilket normalt er en god ting i RDBMS'er. Men per definition betyder dette, at der ikke er nogen dubletter. I vores tilfælde er den primære nøglekolonne et stigende tal, og dens værdi har ingen betydning og er ikke signifikant. Vi er derfor nødt til at ignorere den række, hvis vi vil finde dubletter i de kolonner, der er væsentlig.
Mulighed 1
Vi kan bruge GROUP BY
klausul for at gruppere kolonnerne efter deres signifikante kolonner, og brug derefter den COUNT()
funktion for at returnere antallet af identiske rækker:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Resultat:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Ruff | Robinson | 1 | | Wag | Johnson | 3 | | Woof | Jones | 1 | +-----------+----------+-------+
Vi var i stand til at ekskludere den primære nøglekolonne ved at udelade den fra vores forespørgsel.
Resultatet fortæller os, at der er to rækker indeholdende Bark Smith og tre rækker indeholdende Wag Johnson. Disse er dubletter (eller triplikater i tilfældet med Wag Johnson). De to andre rækker har ingen dubletter.
Mulighed 2
Vi kan ekskludere ikke-duplikater fra outputtet med HAVING
klausul:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Resultat:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Wag | Johnson | 3 | +-----------+----------+-------+
Mulighed 3
Det er også muligt at kontrollere for dubletter på sammenkædede kolonner. For eksempel kan vi bruge CONCAT()
funktion til at sammenkæde vores to kolonner, brug DISTINCT
søgeord for at få forskellige værdier, og brug derefter COUNT()
funktion for at returnere antallet:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Resultat:
+---------------+-------+ | DogName | Count | +---------------+-------+ | Bark Smith | 2 | | Ruff Robinson | 1 | | Wag Johnson | 3 | | Woof Jones | 1 | +---------------+-------+
Mulighed 4
Vi kan bruge ROW_NUMBER()
funktion med PARTITION BY
klausul:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Resultat:
+-------+-----------+----------+------------+ | DogId | FirstName | LastName | Row_Number | +-------+-----------+----------+------------+ | 1 | Bark | Smith | 1 | | 2 | Bark | Smith | 2 | | 4 | Ruff | Robinson | 1 | | 6 | Wag | Johnson | 1 | | 5 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | | 3 | Woof | Jones | 1 | +-------+-----------+----------+------------+
Dette opretter en ny kolonne med et rækkenummer, der stiger, hver gang der er en dublet, men nulstilles igen, når der er en unik række.
I dette tilfælde grupperer vi ikke resultaterne, hvilket betyder, at vi kan se hver dubletrække, inklusive dens unikke identifikatorkolonne.
Mulighed 5
Vi kan også bruge det forrige eksempel som et almindeligt tabeludtryk i en større forespørgsel:
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;
Resultat:
+-------+-----------+----------+------------+ | DogId | FirstName | LastName | Row_Number | +-------+-----------+----------+------------+ | 2 | Bark | Smith | 2 | | 5 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +-------+-----------+----------+------------+
Dette udelukker ikke-duplikater fra outputtet, og det udelukker en række af hver dublet fra outputtet.
Denne forespørgsel kunne bruges som en forløber for en de-duping-operation. Det kan vise os, hvad der vil blive slettet, hvis vi beslutter os for at slette dubletter. For at de-dupere tabellen er alt, hvad vi skal gøre, at erstatte den sidste SELECT *
med DELETE
.
Mulighed 6
Her er en mere kortfattet måde at få det samme output som det foregående eksempel:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Resultat:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Dette eksempel kræver ikke generering af vores eget separate rækkenummer.
Vi kan erstatte SELECT *
med DELETE
for at slette dubletterne.
Mulighed 7
Og endelig, her er en anden mulighed for at returnere dubletter:
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
);
Resultat:
+-------+-----------+----------+-------+-----------+----------+ | DogId | FirstName | LastName | DogId | FirstName | LastName | +-------+-----------+----------+-------+-----------+----------+ | 2 | Bark | Smith | 1 | Bark | Smith | | 7 | Wag | Johnson | 5 | Wag | Johnson | | 7 | Wag | Johnson | 6 | Wag | Johnson | +-------+-----------+----------+-------+-----------+----------+