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

7 modi per trovare righe duplicate in PostgreSQL ignorando la chiave primaria

Ecco sette modi per restituire righe duplicate in PostgreSQL quando quelle righe hanno una chiave primaria o un'altra colonna di identificatore univoco.

Ciò significa che le righe duplicate condividono esattamente gli stessi valori in tutte le colonne ad eccezione della loro chiave primaria/colonna ID univoco.

Dati di esempio

Utilizzeremo i seguenti dati per i nostri esempi:

SELECT * FROM Dogs;

Risultato:

 dogid | firstname | lastname 
-------+-----------+----------
     1 | Bark      | Smith
     2 | Bark      | Smith
     3 | Woof      | Jones
     4 | Ruff      | Robinson
     5 | Wag       | Johnson
     6 | Wag       | Johnson
     7 | Wag       | Johnson

Le prime due righe sono duplicate (tranne per DogId colonna, che è la chiave primaria della tabella e contiene un valore univoco in tutte le righe). Anche le ultime tre righe sono duplicate (ad eccezione di DogId colonna).

La colonna della chiave primaria garantisce che non vi siano righe duplicate, il che è una buona pratica negli RDBMS, poiché le chiavi primarie aiutano a rafforzare l'integrità dei dati. Ma poiché le chiavi primarie impediscono le righe duplicate, possono potenzialmente interferire con la nostra capacità di trovare duplicati.

Nella nostra tabella sopra, la colonna della chiave primaria è un numero incrementale e il suo valore non ha significato e non è significativo. Dobbiamo quindi ignorare quella riga se vogliamo trovare duplicati nelle altre colonne.

Opzione 1

Possiamo usare l'SQL GROUP BY clausola per raggruppare le colonne in base alle colonne significative, quindi utilizzare COUNT() funzione per restituire il numero di righe identiche:

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

Risultato:

 firstname | lastname | count 
-----------+----------+-------
 Ruff      | Robinson |     1
 Wag       | Johnson  |     3
 Woof      | Jones    |     1
 Bark      | Smith    |     2

Qui abbiamo escluso la colonna della chiave primaria omettendola dalla nostra query.

Il risultato ci dice che ci sono tre righe contenenti Wag Johnson e due righe contenenti Bark Smith. Questi sono duplicati (o triplicati nel caso di Wag Johnson). Le altre due righe non hanno duplicati.

Opzione 2

Possiamo escludere i non duplicati dall'output con HAVING clausola:

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

Risultato:

 firstname | lastname | count 
-----------+----------+-------
 Wag       | Johnson  |     3
 Bark      | Smith    |     2

Opzione 3

Ecco un esempio di controllo dei duplicati su colonne concatenate. In questo caso utilizziamo il CONCAT() per concatenare le nostre due colonne, usa il DISTINCT parola chiave per ottenere valori distinti, quindi utilizzare COUNT() funzione per restituire il conteggio:

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

Risultato:

    dogname    | count 
---------------+-------
 Wag Johnson   |     3
 Ruff Robinson |     1
 Woof Jones    |     1
 Bark Smith    |     2

Opzione 4

In alternativa possiamo utilizzare il ROW_NUMBER() funzione finestra:

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

Risultato:

 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

Usando la PARTITION La clausola comporta l'aggiunta di una nuova colonna, con un numero di riga che aumenta ogni volta che c'è un duplicato, ma si reimposta di nuovo quando c'è una riga univoca.

In questo caso non raggruppiamo i risultati, il che significa che possiamo vedere ogni riga duplicata, inclusa la relativa colonna dell'identificatore univoco.

Opzione 5

Possiamo anche utilizzare l'esempio precedente come espressione di tabella comune in una query più ampia:

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;

Risultato:

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

Ciò esclude i non duplicati dall'output ed esclude una riga di ogni duplicato dall'output. In altre parole, mostra solo le righe in eccesso dai duplicati. Queste righe sono le principali candidate per essere eliminate in un'operazione di deduplicazione.

Opzione 6

Ecco un modo più conciso per ottenere lo stesso output dell'esempio precedente:

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

Risultato:

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

Una differenza tra questo esempio e il precedente è che questo esempio non richiede la generazione del nostro numero di riga separato.

Opzione 7

Ecco un'altra opzione per restituire le righe duplicate in 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
);

Risultato:

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