Inilah salah satu solusinya. Saya menguji ini di 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;
Saya menyertakan c2.notes sebagai kunci GROUP BY karena Anda mungkin memiliki lebih dari satu baris dengan catatan bukan nol per nilai driver_id,car_id.
Hasil menggunakan data contoh Anda:
+------+-----------+--------+-------+
| id | driver_id | car_id | notes |
+------+-----------+--------+-------+
| 2 | 1 | 1 | NULL |
| 4 | 2 | 1 | NULL |
| 8 | 3 | 2 | hi |
| 9 | 5 | 3 | NULL |
+------+-----------+--------+-------+
Tentang menghapus. Dalam data contoh Anda, selalu nilai id tertinggi per driver_id &car_id yang ingin Anda pertahankan. Jika Anda dapat mengandalkannya, Anda dapat melakukan penghapusan multi-tabel yang menghapus semua baris yang memiliki baris dengan nilai id yang lebih tinggi dan driver_id &car_id yang sama:
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;
Ini secara alami melewatkan setiap kasus di mana hanya ada satu baris dengan pasangan nilai driver_id &car_id tertentu, karena kondisi inner join memerlukan dua baris dengan nilai id yang berbeda.
Tetapi jika Anda tidak dapat bergantung pada id terbaru per grup yang ingin Anda pertahankan, solusinya lebih kompleks. Ini mungkin lebih kompleks daripada yang layak untuk dipecahkan dalam satu pernyataan, jadi lakukan dalam dua pernyataan.
Saya menguji ini juga, setelah menambahkan beberapa baris lagi untuk pengujian:
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 |
+----+--------+-----------+-------+
Pertama-tama hapus baris dengan catatan nol, di mana ada baris dengan catatan bukan nol.
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 |
+----+--------+-----------+-------+
Kedua, hapus semua kecuali baris id tertinggi dari setiap grup duplikat.
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 |
+----+--------+-----------+-------+