sql >> Databasteknik >  >> RDS >> Mysql

7 sätt att hitta dubbletter av rader medan du ignorerar den primära nyckeln i MySQL

Här är sju sätt att returnera dubbletter av rader i MySQL när dessa rader har en primärnyckel eller annan unik identifierarkolumn.

Exempeldata

Vi använder följande data för våra exempel:

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;

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

Dubblettraderna delar exakt samma värden i alla kolumner förutom deras primärnyckel/unika ID-kolumn.

De två första raderna är dubbletter (förutom DogId kolumn, som är tabellens primärnyckel och innehåller ett unikt värde över alla rader). De sista tre raderna är också dubbletter (förutom DogId kolumn).

Den primära nyckelkolumnen säkerställer att det inte finns några dubbletter av rader, vilket normalt är bra i RDBMS. Men per definition innebär detta att det inte finns några dubbletter. I vårt fall är primärnyckelkolumnen ett ökande tal, och dess värde har ingen betydelse och är inte signifikant. Vi måste därför ignorera den raden om vi vill hitta dubbletter i kolumnerna som är signifikant.

Alternativ 1

Vårt första alternativ är att använda GROUP BY sats för att gruppera kolumnerna efter deras signifikanta kolumner, använd sedan COUNT() funktion för att returnera antalet identiska rader:

SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;

Resultat:

+-----------+----------+-------+
| FirstName | LastName | Count |
+-----------+----------+-------+
| Bark      | Smith    |     2 |
| Woof      | Jones    |     1 |
| Ruff      | Robinson |     1 |
| Wag       | Johnson  |     3 |
+-----------+----------+-------+

Vi kunde ignorera primärnyckelkolumnen genom att utelämna den från vår fråga.

Resultatet berättar att det finns två rader som innehåller Bark Smith och tre rader som innehåller Wag Johnson. Dessa är dubbletter (eller triplikat i fallet med Wag Johnson). De andra två raderna har inga dubbletter.

Alternativ 2

Vi kan utesluta icke-duplikat från utdata 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 |
+-----------+----------+-------+

Alternativ 3

Vi kan också kontrollera om det finns dubbletter på sammanlänkade kolumner. Till exempel kan vi använda CONCAT() funktion för att sammanfoga våra två kolumner, använd DISTINCT nyckelord för att få distinkta värden, använd sedan COUNT() funktion för att returnera antalet:

SELECT
    DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
    COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);

Resultat:

+---------------+-------+
| DogName       | Count |
+---------------+-------+
| Bark Smith    |     2 |
| Woof Jones    |     1 |
| Ruff Robinson |     1 |
| Wag Johnson   |     3 |
+---------------+-------+

Alternativ 4

Vi kan alternativt använda ROW_NUMBER() funktion med PARTITION BY klausul:

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

Resultat:

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

Detta skapar en ny kolumn med ett radnummer som ökar varje gång det finns en dubblett, men återställs igen när det finns en unik rad

Denna teknik ger en möjlig fördel genom att vi inte behöver gruppera resultaten. Det betyder att vi kan se varje dubblettrad, inklusive dess unika identifierarkolumn.

Alternativ 5

Vi kan använda föregående exempel som ett vanligt tabelluttryck i en större fråga:

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;

Resultat:

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

Den här tekniken utesluter icke-dubbletter från utdata, och den exkluderar en rad av varje duplikat från utdata.

Denna fråga kan användas som en föregångare till en de-dupingoperation. Det kan visa oss vad som kommer att raderas om vi bestämmer oss för att ta bort dubbletter. För att de-dupera tabellen behöver vi bara ersätta den sista SELECT * med DELETE .

Alternativ 6

Här är ett mer kortfattat sätt att få samma utdata som föregående exempel:

SELECT * FROM Dogs 
WHERE DogId IN (
    SELECT DogId FROM Dogs 
    WHERE DogId NOT IN (SELECT MIN(DogId) FROM Dogs
    GROUP BY FirstName, LastName)
    );

Resultat:

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

Den här tekniken kräver inte att vi genererar ett separat radnummer med ROW_NUMBER() som i föregående exempel.

Vi kan också ersätta SELECT * med DELETE för att ta bort dubbletterna.

Alternativ 7

Och slutligen, här är ytterligare ett alternativ för att returnera dubbletter:

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

  1. SYS_EXTRACT_UTC() Funktion i Oracle

  2. Importera CSV till MySQL

  3. MariaDB LCASE() Förklarad

  4. SQLite Insert