sql >> Database >  >> RDS >> Mysql

7 manieren om dubbele rijen te vinden terwijl u de primaire sleutel in MySQL negeert

Hier zijn zeven manieren om dubbele rijen in MySQL te retourneren wanneer die rijen een primaire sleutel of een andere unieke identificatiekolom hebben.

Voorbeeldgegevens

We gebruiken de volgende gegevens voor onze voorbeelden:

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;

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 dubbele rijen delen exact dezelfde waarden in alle kolommen, behalve hun primaire sleutel/unieke ID-kolom.

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

Onze eerste optie is om de GROUP BY . te 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 |
| Woof      | Jones    |     1 |
| Ruff      | Robinson |     1 |
| Wag       | Johnson  |     3 |
+-----------+----------+-------+

We konden de primaire sleutelkolom negeren door deze weg te laten uit 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

We kunnen ook 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 |
| Woof Jones    |     1 |
| Ruff Robinson |     1 |
| Wag Johnson   |     3 |
+---------------+-------+

Optie 4

We kunnen ook de ROW_NUMBER() . gebruiken functie met de PARTITION BY clausule:

SELECT 
    *,
    ROW_NUMBER() OVER ( 
        PARTITION BY FirstName, LastName 
        ORDER BY FirstName, LastName
        ) AS rn
FROM Dogs;

Resultaat:

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

Hiermee wordt een nieuwe kolom gemaakt met een rijnummer dat wordt verhoogd telkens wanneer er een duplicaat is, maar opnieuw wordt ingesteld wanneer er een unieke rij is

Deze techniek biedt een mogelijk voordeel doordat we de resultaten niet hoeven te groeperen. Dit betekent dat we elke dubbele rij kunnen zien, inclusief de unieke identificatiekolom.

Optie 5

We kunnen het vorige voorbeeld 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 rn
        FROM Dogs
    )
SELECT * FROM cte WHERE rn <> 1;

Resultaat:

+-------+-----------+----------+----+
| DogId | FirstName | LastName | rn |
+-------+-----------+----------+----+
|     2 | Bark      | Smith    |  2 |
|     6 | Wag       | Johnson  |  2 |
|     7 | Wag       | Johnson  |  3 |
+-------+-----------+----------+----+

Deze techniek 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 
    WHERE DogId NOT IN (SELECT MIN(DogId) FROM Dogs
    GROUP BY FirstName, LastName)
    );

Resultaat:

+-------+-----------+----------+
| DogId | FirstName | LastName |
+-------+-----------+----------+
|     2 | Bark      | Smith    |
|     6 | Wag       | Johnson  |
|     7 | Wag       | Johnson  |
+-------+-----------+----------+

Voor deze techniek hoeven we geen apart rijnummer te genereren met ROW_NUMBER() zoals in het vorige voorbeeld.

We kunnen ook SELECT * . vervangen met DELETE om de duplicaten te verwijderen.

Optie 7

En tot slot, hier is nog een 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. MySQL match() against() - volgorde op relevantie en kolom?

  2. Schema Switch-A-Roo:deel 2

  3. PL/SQL Bulk Collect met LIMIT-clausule in Oracle Database

  4. Oracle E-Business Suite-architectuur in 12.2