sql >> Database teknologi >  >> RDS >> Mysql

7 måder at finde dublerede rækker, mens du ignorerer den primære nøgle i MySQL

Her er syv måder at returnere duplikerede rækker i MySQL, når disse rækker har en primær nøgle eller en anden unik identifikatorkolonne.

Eksempeldata

Vi bruger følgende data til vores eksempler:

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

De dublerede rækker deler nøjagtigt de samme værdier på tværs af alle kolonner undtagen deres primære nøgle/unikke id-kolonne.

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.

Valgmulighed 1

Vores første mulighed er at bruge GROUP BY klausul for at gruppere kolonnerne efter deres signifikante kolonner, og brug derefter 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 |
| Woof      | Jones    |     1 |
| Ruff      | Robinson |     1 |
| Wag       | Johnson  |     3 |
+-----------+----------+-------+

Vi var i stand til at ignorere 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.

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

Valgmulighed 3

Vi kan også 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 |
| Woof Jones    |     1 |
| Ruff Robinson |     1 |
| Wag Johnson   |     3 |
+---------------+-------+

Valgmulighed 4

Vi kan alternativt bruge 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 |
+-------+-----------+----------+----+

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

Denne teknik giver en mulig fordel ved, at vi ikke behøver at gruppere resultaterne. Det betyder, at vi kan se hver dubletrække, inklusive dens unikke identifikatorkolonne.

Valgmulighed 5

Vi kan bruge det foregående 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 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 |
+-------+-----------+----------+----+

Denne teknik udelukker ikke-duplikater fra outputtet, og den udelukker en række af hver dublet fra outputtet.

Denne forespørgsel kan 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 .

Valgmulighed 6

Her er en mere kortfattet måde at få det samme output som det forrige eksempel:

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

Denne teknik kræver ikke, at vi genererer et separat rækkenummer med ROW_NUMBER() ligesom i det foregående eksempel.

Vi kan også erstatte SELECT * med DELETE for at slette dubletterne.

Valgmulighed 7

Og endelig, her er endnu en 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  |
+-------+-----------+----------+-------+-----------+----------+

  1. Beregn åbningstider mellem to datoer

  2. Android:Sådan indlæses et billede dynamisk fra serveren ved dets navn fra SQlite

  3. MySQL Bestil efter et nummer, null sidst

  4. SQL-netværksgrænseflader, fejl:50 - Lokal databasekørselsfejl opstod. Kan ikke oprette en automatisk forekomst