SQLite
 sql >> Database >  >> RDS >> SQLite

11 modi per trovare righe duplicate ignorando la chiave primaria in SQLite

Ecco undici opzioni per restituire righe duplicate in SQLite quando quelle righe hanno una chiave primaria o qualche altra colonna di identificatore univoco (ma vuoi ignorare la chiave primaria).

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 eseguire una query con GROUP BY per raggruppare le colonne in base alle colonne significative, quindi utilizzare il COUNT() funzione per restituire il numero di righe identiche:

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

Risultato:

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

Qui abbiamo escluso la colonna della chiave primaria omettendola dalla nostra query. Lo abbiamo anche ordinato per conteggio in ordine decrescente, in modo che i duplicati vengano visualizzati per primi.

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 usare il HAVING clausola per escludere i non duplicati dall'output:

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

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 DISTINCT parola chiave per ottenere valori distinti, quindi utilizzare COUNT() funzione per restituire il conteggio:

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

Risultato:

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

Opzione 4

Per impostazione predefinita, ogni riga in SQLite ha una colonna speciale, solitamente chiamata rowid , che identifica in modo univoco quella riga all'interno della tabella. A meno che non sia stato esplicitamente rimosso dalla tabella, puoi usarlo come identificatore univoco per ogni riga.

Possiamo quindi utilizzare il rowid nella nostra domanda:

SELECT * FROM Dogs
WHERE EXISTS (
  SELECT 1 FROM Dogs d2 
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
  AND Dogs.rowid > d2.rowid
);

Risultato:

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

Potremmo sostituire SELECT * con DELETE per eseguire un'operazione di deduplicazione sul tavolo.

Nota che avremmo potuto usare DogId colonna (la nostra chiave primaria) invece di rowid se volessimo. Detto questo, il rowid può essere utile se per qualche motivo non puoi utilizzare la colonna della chiave primaria o se la tabella non ha una chiave primaria.

Opzione 5

Ecco un'altra query che utilizza rowid :

SELECT * FROM Dogs
WHERE rowid > (
  SELECT MIN(rowid) FROM Dogs d2  
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
);

Risultato:

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

Come nell'esempio precedente, potremmo sostituire SELECT * con DELETE per eliminare le righe duplicate.

Opzione 6

I due rowid le opzioni precedenti sono ottime se devi ignorare completamente la chiave primaria nella tua query (o se non hai affatto una colonna di chiave primaria). Tuttavia, come accennato, c'è ancora la possibilità di sostituire rowid con la colonna della chiave primaria, nel nostro caso il DogId colonna:

SELECT * FROM Dogs
WHERE EXISTS (
  SELECT 1 FROM Dogs d2 
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
  AND Dogs.DogId > d2.DogId
);

Risultato:

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

Opzione 7

Ed ecco l'altra query con rowid sostituito da DogId colonna:

SELECT * FROM Dogs
WHERE DogId > (
  SELECT MIN(DogId) FROM Dogs d2  
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
);

Risultato:

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

Opzione 8

Un altro modo per farlo è usare 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 9

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.

Opzione 10

Ecco un altro modo 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
-----  ---------  --------
2      Bark       Smith   
6      Wag        Johnson 
7      Wag        Johnson 

Opzione 11

Ecco un'altra opzione per selezionare i duplicati dalla nostra tabella:

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