Trovare ed eliminare duplicati

La duplicazione di dati non dovrebbe mai avvenire in un database bene organizzato, ma talvolta, quando si ha a che fare con dati ereditati da applicazioni poco accurate, può accadere di ritrovarsi con una tabella che contiene record duplicati.

In questa poco piacevole situazione, ci sono tre tipi di operazioni che si vorrebbero eseguire:

  • Elencare i record senza duplicati;
  • Elencare i valori duplicati;
  • Eliminare i duplicati.

Prendiamo ad esempio una tabella con qualche record duplicato (per esigenze di spazio, la facciamo corta, ma supponete di avere svariate migliaia di record).


mysql> SELECT * FROM condoppi;
+---+------+-----+
| i | a | b |
+---+------+-----+
| 1 | aaa | xxx |
| 2 | bbb | yyy |
| 3 | aaa | yyy |
| 4 | ccc | www |
| 5 | aaa | xxx |
| 6 | ddd | zzz |
| 7 | aaa | xxx |
| 8 | bbb | yyy |
| 9 | ccc | www |
+---+------+-----+
9 rows in set (0.18 sec)

La prima esigenza, vedere i record senza doppi, viene risolta facilmente usando la clausola DISTINCT:


mysql> SELECT DISTINCT a, b FROM condoppi;
+------+-----+
| a | b |
+------+-----+
| aaa | xxx |
| aaa | yyy |
| bbb | yyy |
| ccc | www |
| ddd | zzz |
+------+-----+
5 rows in set (0.12 sec)

Facilissimo. Basta premettere DISTINCT alla lista dei campi per avere un elenco pulito, senza duplicati.

Notate che se avessi inserito fra i campi anche la chiave primaria (campo “i”), il DBMS mi avrebbe stampato tutti i record, perché ovviamente sono differenziati grazie al campo univoco. La clausola DISTINCT è anche utile per avere un elenco dei valori distinti (appunto) per una data colonna. Per la seconda esigenza, vedere quali valori sono doppiati, non c’è formula magica immediata, ma bisogna sforzarsi un po’ di più.

Il metodo consiste nel raggruppare i valori con un conteggio, e considerare solo quelli maggiori di 1. Si noti la clausola HAVING che (a differenza di WHERE) viene valutata dopo l’operazone di raggruppamento.


mysql> SELECT a, b COUNT(*) AS quanti
FROM condoppi
GROUP BY a, b
HAVING quanti > 1;
+------+-----+--------+
| a | b | quanti |
+------+-----+--------+
| aaa | xxx | 2 |
| bbb | yyy | 2 |
| ccc | www | 2 |
+------+-----+--------+
3 rows in set (0.39 sec)

Così possiamo vedere quali sono i valori (o le combinazioni di valori) che sono registrati più di una volta.

Infine, se vogliamo cancellare dalla tabella i valori doppi, esiste un metodo molto semplice e pratico: aggiungere un indice univoco alla tabella, ma usando la clausola IGNORE, per far sì che il DBMS non si fermi al primo errore di record duplicato, ma vada avanti, di fatto saltando l’inserimento dei record con valori già inseriti.


mysql> ALTER IGNORE TABLE condoppi ADD UNIQUE KEY (a, b) ;
Query OK, 9 rows affected (0.54 sec)
Records: 9 Duplicati: 4 Avvertimenti: 0
mysql> SELECT * FROM condoppi;
+---+------+-----+
| i | a | b |
+---+------+-----+
| 1 | aaa | xxx |
| 2 | bbb | yyy |
| 3 | aaa | yyy |
| 4 | ccc | www |
| 6 | ddd | zzz |
+---+------+-----+
5 rows in set (0.02 sec)