Hier zijn zeven manieren om dubbele rijen in MariaDB te retourneren wanneer die rijen een primaire sleutel of een andere unieke identificatiekolom hebben.
Daarom delen de dubbele rijen exact dezelfde waarden in alle kolommen behalve hun unieke identificatiekolom.
Voorbeeldgegevens
We gebruiken de volgende gegevens voor onze voorbeelden:
SELECT * FROM Dogs;
Resultaat:
+-------+-----------+----------+ | 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 eerste twee rijen zijn duplicaten (behalve de DogId
kolom, de primaire sleutel van de tabel, en bevat een unieke waarde voor alle rijen). De laatste drie rijen zijn ook duplicaten (behalve de DogId
kolom).
De primaire sleutelkolom zorgt ervoor dat er geen dubbele rijen zijn, wat normaal gesproken een goede zaak is in RDBMS'en. Dit betekent echter per definitie dat er geen duplicaten zijn. In ons geval is de primaire sleutelkolom een oplopend getal, en de waarde ervan heeft geen betekenis en is niet significant. We moeten die rij daarom negeren als we duplicaten willen vinden in de kolommen die zijn significant.
Optie 1
We kunnen de GROUP BY
. gebruiken clausule om de kolommen te groeperen op hun significante kolommen, gebruik dan de COUNT()
functie om het aantal identieke rijen terug te geven:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Resultaat:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Ruff | Robinson | 1 | | Wag | Johnson | 3 | | Woof | Jones | 1 | +-----------+----------+-------+
We konden de primaire sleutelkolom uitsluiten door deze weg te laten in onze zoekopdracht.
Het resultaat vertelt ons dat er twee rijen zijn met Bark Smith en drie rijen met Wag Johnson. Dit zijn duplicaten (of drievoud in het geval van Wag Johnson). De andere twee rijen hebben geen dubbele rijen.
Optie 2
We kunnen niet-duplicaten uitsluiten van de uitvoer met de HAVING
clausule:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Resultaat:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Wag | Johnson | 3 | +-----------+----------+-------+
Optie 3
Het is ook mogelijk om te controleren op duplicaten op aaneengeschakelde kolommen. We kunnen bijvoorbeeld de CONCAT()
. gebruiken functie om onze twee kolommen samen te voegen, gebruik de DISTINCT
zoekwoord om verschillende waarden te krijgen, gebruik dan de COUNT()
functie om de telling terug te geven:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Resultaat:
+---------------+-------+ | DogName | Count | +---------------+-------+ | Bark Smith | 2 | | Ruff Robinson | 1 | | Wag Johnson | 3 | | Woof Jones | 1 | +---------------+-------+
Optie 4
We kunnen de ROW_NUMBER()
. gebruiken functie met de PARTITION BY
clausule:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Resultaat:
+-------+-----------+----------+------------+ | 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 | +-------+-----------+----------+------------+
Dit creëert een nieuwe kolom met een rijnummer dat elke keer dat er een duplicaat is, wordt verhoogd, maar opnieuw wordt hersteld wanneer er een unieke rij is.
In dit geval groeperen we de resultaten niet, wat betekent dat we elke dubbele rij kunnen zien, inclusief de unieke ID-kolom.
Optie 5
We kunnen het vorige voorbeeld ook gebruiken als een algemene tabeluitdrukking in een grotere query:
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;
Resultaat:
+-------+-----------+----------+------------+ | DogId | FirstName | LastName | Row_Number | +-------+-----------+----------+------------+ | 2 | Bark | Smith | 2 | | 5 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +-------+-----------+----------+------------+
Dit sluit niet-duplicaten uit van de uitvoer en sluit één rij van elk duplicaat uit van de uitvoer.
Deze query kan worden gebruikt als een voorloper van een ontdubbelingsoperatie. Het kan ons laten zien wat er wordt verwijderd als we besluiten om duplicaten te verwijderen. Om de tabel te ontdubbelen, hoeven we alleen de laatste SELECT *
. te vervangen met DELETE
.
Optie 6
Hier is een beknoptere manier om dezelfde uitvoer te krijgen als in het vorige voorbeeld:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Resultaat:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Voor dit voorbeeld is het niet nodig om ons eigen afzonderlijke rijnummer te genereren.
We kunnen SELECT *
vervangen met DELETE
om de duplicaten te verwijderen.
Optie 7
En tot slot, hier is nog een andere optie voor het retourneren van duplicaten:
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
);
Resultaat:
+-------+-----------+----------+-------+-----------+----------+ | DogId | FirstName | LastName | DogId | FirstName | LastName | +-------+-----------+----------+-------+-----------+----------+ | 2 | Bark | Smith | 1 | Bark | Smith | | 7 | Wag | Johnson | 5 | Wag | Johnson | | 7 | Wag | Johnson | 6 | Wag | Johnson | +-------+-----------+----------+-------+-----------+----------+