sql >> Database teknologi >  >> RDS >> PostgreSQL

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

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

Det betyder, at de duplikerede rækker deler nøjagtig de samme værdier på tværs af alle kolonner med undtagelse af deres primære nøgle/unik ID-kolonne.

Eksempel på data

Vi bruger følgende data til vores eksempler:

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 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).

Primærnøglekolonnen sikrer, at der ikke er duplikerede rækker, hvilket er god praksis i RDBMS'er, fordi primærnøgler hjælper med at håndhæve dataintegritet. Men fordi primærnøgler forhindrer duplikerede rækker, har de potentialet til at forstyrre vores evne til at finde dubletter.

I vores tabel ovenfor 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 andre kolonner.

Mulighed 1

Vi kan bruge SQL 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 
-----------+----------+-------
 Ruff      | Robinson |     1
 Wag       | Johnson  |     3
 Woof      | Jones    |     1
 Bark      | Smith    |     2

Her udelukkede vi primærnøglekolonnen ved at udelade den fra vores forespørgsel.

Resultatet fortæller os, at der er tre rækker indeholdende Wag Johnson og to rækker indeholdende Bark Smith. Disse er dubletter (eller triplikater i tilfældet med Wag Johnson). De to andre rækker har ingen dubletter.

Mulighed 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 
-----------+----------+-------
 Wag       | Johnson  |     3
 Bark      | Smith    |     2

Mulighed 3

Her er et eksempel på kontrol for dubletter på sammenkædede kolonner. I dette tilfælde bruger vi 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 
---------------+-------
 Wag Johnson   |     3
 Ruff Robinson |     1
 Woof Jones    |     1
 Bark Smith    |     2

Mulighed 4

Vi kan alternativt bruge ROW_NUMBER() vinduesfunktion:

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

Resultat:

 dogid | firstname | lastname | row_number 
-------+-----------+----------+------------
     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

Brug af PARTITION klausul resulterer i, at der tilføjes 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.

I dette tilfælde grupperer vi ikke resultaterne, hvilket betyder, at vi kan se hver dubletrække, inklusive dens unikke identifikatorkolonne.

Mulighed 5

Vi kan også bruge det forrige 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 Row_Number
        FROM Dogs
    )
SELECT * FROM cte WHERE Row_Number <> 1;

Resultat:

 dogid | firstname | lastname | row_number 
-------+-----------+----------+------------
     2 | Bark      | Smith    |          2
     6 | Wag       | Johnson  |          2
     7 | Wag       | Johnson  |          3

Dette udelukker ikke-duplikater fra outputtet, og det udelukker en række af hver dublet fra outputtet. Med andre ord viser den kun de overskydende rækker fra dubletterne. Disse rækker er primære kandidater til at blive slettet i en de-duping-operation.

Mulighed 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 
    EXCEPT SELECT MIN(DogId) FROM Dogs 
    GROUP BY FirstName, LastName
    );

Resultat:

 dogid | firstname | lastname 
-------+-----------+----------
     6 | Wag       | Johnson
     2 | Bark      | Smith
     7 | Wag       | Johnson

En forskel mellem dette eksempel og det foregående er, at dette eksempel ikke kræver at generere vores eget separate rækkenummer.

Mulighed 7

Her er endnu en mulighed for at returnere duplikerede rækker i Postgres:

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. få nyt SQL record ID

  2. UNION-forespørgsel med kodetænderens aktive registreringsmønster

  3. MySQL bestil efter før gruppe efter

  4. CONVERT() fra dato/tid til strengeksempler i SQL Server