web-dev-qa-db-fra.com

Comment supprimer les doublons dans la table SQL en fonction de plusieurs champs

J'ai une table de jeux, qui est décrite comme suit:

+---------------+-------------+------+-----+---------+----------------+
| Field         | Type        | Null | Key | Default | Extra          |
+---------------+-------------+------+-----+---------+----------------+
| id            | int(11)     | NO   | PRI | NULL    | auto_increment |
| date          | date        | NO   |     | NULL    |                |
| time          | time        | NO   |     | NULL    |                |
| hometeam_id   | int(11)     | NO   | MUL | NULL    |                |
| awayteam_id   | int(11)     | NO   | MUL | NULL    |                |
| locationcity  | varchar(30) | NO   |     | NULL    |                |
| locationstate | varchar(20) | NO   |     | NULL    |                |
+---------------+-------------+------+-----+---------+----------------+

Mais chaque jeu a une entrée en double dans le tableau quelque part, car chaque jeu était dans les horaires de deux équipes. Existe-t-il une instruction SQL que je peux utiliser pour parcourir et supprimer tous les doublons en fonction des champs identiques de date, heure, hometeam_id, awayteam_id, locationcity et locationstate?

24
cfrederich

Vous devez pouvoir effectuer une sous-requête corrélée pour supprimer les données. Recherchez toutes les lignes qui sont en double et supprimez toutes sauf celle avec le plus petit identifiant. Pour MYSQL, une jointure interne (équivalent fonctionnel d'EXISTS) doit être utilisée, comme ceci:

delete games from games inner join 
    (select  min(id) minid, date, time,
             hometeam_id, awayteam_id, locationcity, locationstate
     from games 
     group by date, time, hometeam_id, 
              awayteam_id, locationcity, locationstate
     having count(1) > 1) as duplicates
   on (duplicates.date = games.date
   and duplicates.time = games.time
   and duplicates.hometeam_id = games.hometeam_id
   and duplicates.awayteam_id = games.awayteam_id
   and duplicates.locationcity = games.locationcity
   and duplicates.locationstate = games.locationstate
   and duplicates.minid <> games.id)

Pour tester, remplacez delete games from games avec select * from games. Ne vous contentez pas d'exécuter une suppression sur votre base de données :-)

45
N West

Vous pouvez essayer une telle requête:

DELETE FROM table_name AS t1
WHERE EXISTS (
 SELECT 1 FROM table_name AS t2 
 WHERE t2.date = t1.date 
 AND t2.time = t1.time 
 AND t2.hometeam_id = t1.hometeam_id 
 AND t2.awayteam_id = t1.awayteam_id 
 AND t2.locationcity = t1.locationcity 
 AND t2.id > t1.id )

Cela ne laissera dans la base de données qu'un exemple de chaque instance de jeu qui a le plus petit identifiant.

13
Grigor Gevorgyan

La meilleure chose qui a fonctionné pour moi a été de recréer la table.

CREATE TABLE newtable SELECT * FROM oldtable GROUP BY field1,field2;

Vous pouvez ensuite renommer.

7
Ali Hashemi

Pour obtenir la liste des entrées en double correspondant à deux champs

select t.ID, t.field1, t.field2
from (
  select field1, field2
  from table_name
  group by field1, field2
  having count(*) > 1) x, table_name t
where x.field1 = t.field1 and x.field2 = t.field2
order by t.field1, t.field2

Et pour supprimer tous les doublons uniquement

DELETE x 
FROM table_name x
JOIN table_name y
ON y.field1= x.field1
AND y.field2 = x.field2
AND y.id < x.id;
5
Rem
select orig.id,
       dupl.id
from   games   orig, 
       games   dupl
where  orig.date   =    dupl.date
and    orig.time   =    dupl.time
and    orig.hometeam_id = dupl.hometeam_id
and    orig. awayteam_id = dupl.awayeam_id
and    orig.locationcity = dupl.locationcity
and    orig.locationstate = dupl.locationstate
and    orig.id     <    dupl.id

cela devrait vous donner les doublons; vous pouvez l'utiliser comme sous-requête pour spécifier les ID à supprimer.

4
Neville Kuyt
delete from games 
   where id not in 
   (select max(id)  from games 
    group by date, time, hometeam_id, awayteam_id, locationcity, locationstate 
    );

Workaround

select max(id)  id from games 
    group by date, time, hometeam_id, awayteam_id, locationcity, locationstate
into table temp_table;

delete from games where id in (select id from temp);
2
piotrpo

Tant que vous n'obtenez pas l'id (clé primaire) de la table dans votre requête de sélection et que les autres données sont exactement les mêmes, vous pouvez utiliser SELECT DISTINCT pour éviter d'obtenir des résultats en double.

2
Wicked Coder
DELETE FROM table
WHERE id = 
    (SELECT t.id
    FROM table as t
    JOIN (table as tj ON (t.date = tj.data
                          AND t.hometeam_id = tj.hometeam_id
                          AND t.awayteam_id = tj.awayteam_id
                          ...))
1
limscoder