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