Mysql
 sql >> база данни >  >> RDS >> Mysql

Как да изберете и/или изтриете всички, освен един ред от всеки набор от дубликати в таблица?

Ето едно решение. Тествах това на 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;

Включвам c2.notes като ключ GROUP BY, защото може да имате повече от един ред с ненулеви бележки за стойности на driver_id,car_id.

Резултат, използвайки вашите примерни данни:

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

Относно изтриването. Във вашите примерни данни това винаги е най-високата стойност на идентификатор за driver_id и car_id, които искате да запазите. Ако можете да разчитате на това, можете да направите изтриване на няколко таблици, което изтрива всички редове, за които съществува ред с по-висока стойност на идентификатора и същия 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;

Това естествено пропуска всички случаи, при които съществува само един ред с дадена двойка стойности driver_id и car_id, тъй като условията на вътрешното свързване изискват два реда с различни стойности на идентификатора.

Но ако не можете да разчитате на последния идентификатор на група, който искате да запазите, решението е по-сложно. Вероятно е по-сложно, отколкото си струва да се реши с едно твърдение, така че го направете с две изявления.

Тествах и това, след като добавих още няколко реда за тестване:

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

Първо изтрийте редове с нулеви бележки, където съществува ред с ненулеви бележки.

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

Второ, изтрийте всички редове с най-висок идентификатор от всяка група дубликати.

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Динамичен попълнен падащ списък PHP MySQL

  2. Засяване на SQLite RANDOM()

  3. Mysqli не позволява множество заявки?

  4. Колко колони в MySQL таблицата

  5. Арабски символ ??????? на php и mysql