sql >> Database >  >> RDS >> MariaDB

7 manieren om dubbele rijen met een primaire sleutel in MariaDB te retourneren

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  |
+-------+-----------+----------+-------+-----------+----------+

  1. Laatst bekende waarde ophalen voor elke kolom van een rij

  2. Verbeter de databaseprestaties met 400%

  3. UNIEKE beperking versus controleren vóór INSERT

  4. SQL-editorbestanden herstellen (query's, procedures) na Toad voor Oracle-crashes of vastlopen