Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment sélectionner et/ou supprimer toutes les lignes sauf une de chaque ensemble de doublons dans une table ?

Voici une solution. J'ai testé cela sur MySQL 5.5.8.

SELECT MAX(COALESCE(c2.id, c1.id)) AS id,
 c1.driver_id, c1.car_id,
 c2.notes AS notes
FROM cars_drivers AS c1
LEFT OUTER JOIN cars_drivers AS c2
 ON (c1.driver_id,c1.car_id) = (c2.driver_id,c2.car_id) AND c2.notes IS NOT NULL
GROUP BY c1.driver_id, c1.car_id, c2.notes;

J'inclus c2.notes en tant que clé GROUP BY car vous pouvez avoir plusieurs lignes avec des notes non nulles par valeurs de driver_id,car_id.

Résultat utilisant vos données d'exemple :

+------+-----------+--------+-------+
| id   | driver_id | car_id | notes |
+------+-----------+--------+-------+
|    2 |         1 |      1 | NULL  |
|    4 |         2 |      1 | NULL  |
|    8 |         3 |      2 | hi    |
|    9 |         5 |      3 | NULL  |
+------+-----------+--------+-------+

Concernant la suppression. Dans votre exemple de données, c'est toujours la valeur d'identifiant la plus élevée par driver_id &car_id que vous souhaitez conserver. Si vous pouvez compter sur cela, vous pouvez effectuer une suppression multi-tables qui supprime toutes les lignes pour lesquelles une ligne avec une valeur d'identifiant plus élevée et les mêmes driver_id &car_id existe :

DELETE c1 FROM cars_drivers AS c1 INNER JOIN cars_drivers AS c2
 ON (c1.driver_id,c1.car_id) = (c2.driver_id,c2.car_id) AND c1.id < c2.id;

Cela ignore naturellement tous les cas où une seule ligne existe avec une paire donnée de valeurs driver_id &car_id, car les conditions de la jointure interne nécessitent deux lignes avec des valeurs id différentes.

Mais si vous ne pouvez pas compter sur le dernier identifiant par groupe étant celui que vous souhaitez conserver, la solution est plus complexe. C'est probablement plus complexe qu'il ne vaut la peine de le résoudre en une seule instruction, alors faites-le en deux.

J'ai également testé cela, après avoir ajouté quelques lignes supplémentaires pour les tests :

INSERT INTO cars_drivers VALUES (10,2,3,NULL), (11,2,3,'bye');

+----+--------+-----------+-------+
| id | car_id | driver_id | notes |
+----+--------+-----------+-------+
|  1 |      1 |         1 | NULL  |
|  2 |      1 |         1 | NULL  |
|  3 |      1 |         2 | NULL  |
|  4 |      1 |         2 | NULL  |
|  5 |      2 |         3 | NULL  |
|  6 |      2 |         3 | NULL  |
|  7 |      2 |         3 | NULL  |
|  8 |      2 |         3 | hi    |
|  9 |      3 |         5 | NULL  |
| 10 |      2 |         3 | NULL  |
| 11 |      2 |         3 | bye   |
+----+--------+-----------+-------+

Supprimez d'abord les lignes avec des notes nulles, là où il existe une ligne avec des notes non nulles.

DELETE c1 FROM cars_drivers AS c1 INNER JOIN cars_drivers AS c2
 ON (c1.driver_id,c1.car_id) = (c2.driver_id,c2.car_id)
WHERE c1.notes IS NULL AND c2.notes IS NOT NULL;

+----+--------+-----------+-------+
| id | car_id | driver_id | notes |
+----+--------+-----------+-------+
|  1 |      1 |         1 | NULL  |
|  2 |      1 |         1 | NULL  |
|  3 |      1 |         2 | NULL  |
|  4 |      1 |         2 | NULL  |
|  8 |      2 |         3 | hi    |
|  9 |      3 |         5 | NULL  |
| 11 |      2 |         3 | bye   |
+----+--------+-----------+-------+

Deuxièmement, supprimez toutes les lignes sauf la ligne avec l'ID le plus élevé de chaque groupe de doublons.

DELETE c1 FROM cars_drivers AS c1 INNER JOIN cars_drivers AS c2
 ON (c1.driver_id,c1.car_id) = (c2.driver_id,c2.car_id) AND c1.id < c2.id;

+----+--------+-----------+-------+
| id | car_id | driver_id | notes |
+----+--------+-----------+-------+
|  2 |      1 |         1 | NULL  |
|  4 |      1 |         2 | NULL  |
|  9 |      3 |         5 | NULL  |
| 11 |      2 |         3 | bye   |
+----+--------+-----------+-------+