sql >> Databáze >  >> RDS >> Mysql

Jak vybrat a/nebo odstranit všechny kromě jednoho řádku každé sady duplikátů v tabulce?

Zde je jedno řešení. Testoval jsem to na 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;

Zahrnuji c2.notes jako klíč GROUP BY, protože můžete mít více než jeden řádek s nenulovými poznámkami na hodnoty driver_id, car_id.

Výsledek pomocí vašich vzorových dat:

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

Ohledně mazání. Ve vašich vzorových datech je to vždy nejvyšší hodnota id na driver_id &car_id, kterou chcete zachovat. Pokud se na to můžete spolehnout, můžete provést odstranění více tabulek, které odstraní všechny řádky, pro které existuje řádek s vyšší hodnotou id a stejným driver_id &car_id:

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;

To přirozeně přeskočí všechny případy, kdy existuje pouze jeden řádek s danou dvojicí hodnot driver_id &car_id, protože podmínky vnitřního spojení vyžadují dva řádky s různými hodnotami id.

Ale pokud se nemůžete spolehnout na to, že nejnovější id na skupinu je ta, kterou si chcete ponechat, řešení je složitější. Je to pravděpodobně složitější, než by stálo za to vyřešit v jednom příkazu, takže to udělejte ve dvou příkazech.

Testoval jsem to také po přidání několika dalších řádků pro testování:

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   |
+----+--------+-----------+-------+

Nejprve odstraňte řádky s nulovými poznámkami, kde existuje řádek s nenulovými poznámkami.

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   |
+----+--------+-----------+-------+

Zadruhé odstraňte z každé skupiny duplikátů všechny řádky kromě nejvyššího ID.

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   |
+----+--------+-----------+-------+


  1. pgAdmin III Proč jsou výsledky dotazů zkráceny?

  2. Mysql DateTime group o 15 minut

  3. Chyba MySQL při vytváření cizího klíče pomocí migrace Laravel

  4. MySQL porovnává znaky Unicode s verzí ASCII