sql >> Databasteknik >  >> RDS >> Mysql

Hur man väljer och/eller tar bort alla utom en rad av varje uppsättning dubbletter i en tabell?

Här är en lösning. Jag testade detta på 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;

Jag inkluderar c2.notes som en GROUP BY-nyckel eftersom du kan ha mer än en rad med icke-nullnoter per värden för driver_id,car_id.

Resultat med din exempeldata:

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

Angående radering. I din exempeldata är det alltid det högsta id-värdet per driver_id &car_id som du vill behålla. Om du kan lita på det kan du göra en radering av flera tabeller som tar bort alla rader för vilka det finns en rad med ett högre id-värde och samma 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;

Detta hoppar naturligtvis över alla fall där endast en rad existerar med ett givet par av driver_id &car_id-värden, eftersom villkoren för den inre kopplingen kräver två rader med olika id-värden.

Men om du inte kan lita på att det senaste id per grupp är det du vill behålla är lösningen mer komplex. Det är förmodligen mer komplext än det är värt att lösa i ett påstående, så gör det i två påståenden.

Jag testade detta också efter att ha lagt till ytterligare ett par rader för testning:

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

Ta först bort rader med nollnoteringar, där det finns en rad med icke-nullnoter.

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

För det andra, ta bort alla utom raden med högsta ID från varje grupp av dubbletter.

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. Dumpa filen MySQL 5.6.10

  2. Slå samman radvärden till en CSV (a.k.a GROUP_CONCAT för SQL Server)

  3. Få alla åtgärder från de tre senaste användarna

  4. PHP konvertera från MySql till Excel Spreadsheet Autosize kolumner