web-dev-qa-db-fra.com

Comment supprimer les enregistrements en double dans MySQL, dans une table sans ID?

J'ai besoin de supprimer les enregistrements en double dans ce tableau. Cependant, il n'y a pas de id pour chaque ligne.

Exemples de données

+---------+--------+----------+
| product | amount | quantity |
+---------+--------+----------+
| table   |   2000 |        5 |
| chair   |    300 |       25 |
| TV      |  30000 |        4 |
| bike    |    300 |       25 |
| table   |   2000 |        5 |
| chair   |    300 |       25 |
| chair   |    300 |       25 |
+---------+--------+----------+

Résultats attendus

J'ai besoin d'obtenir ce résultat.

+---------+--------+----------+
| product | amount | quantity |
+---------+--------+----------+
| table   |   2000 |        5 |
| chair   |    300 |       25 |
| TV      |  30000 |        4 |
| bike    |    300 |       25 |
+---------+--------+----------+

Script avec ID

S'il y avait un id, j'aurais pu utiliser:

DELETE p1 FROM products p1
INNER JOIN products p2 
WHERE p1.id < p2.id AND p1.product = p2.product;
1
Edwin Babu

Il n'y a aucune combinaison de champs qui identifie l'enregistrement de manière unique.

Je vois au moins 2 solutions différentes.

Première solution: déplacer des enregistrements uniques vers une copie de la table et remplacer la table d'origine.

CREATE TABLE temp LIKE products;
INSERT INTO temp 
    SELECT DISTINCT * FROM products;
DROP TABLE products;
RENAME TABLE temp TO products;

Deuxième solution: ajoutez l'auto-incrémentation temporaire, supprimez les enregistrements qui l'utilisent et supprimez le champ temporaire.

ALTER TABLE products ADD COLUMN temp SERIAL PRIMARY KEY;
DELETE t1.* 
    FROM products t1 
    LEFT JOIN ( SELECT MIN(temp) mintemp 
                FROM products
                GROUP BY field1,field2 /* , ... */ , fieldN) t2 
        ON t1.temp=t2.mintemp 
    WHERE t2.mintemp IS NULL;
ALTER TABLE products DROP COLUMN temp;


MISE À JOUR

Dans la deuxième variante: la définition de colonne supplémentaire en tant que clé primaire est redondante. Il suffit d'utiliser

ALTER TABLE products ADD COLUMN temp SERIAL;
13
Akina

En dehors de la réponse d'Akinas, vous pouvez supprimer les deux lignes, puis en insérer une.

Vous devez également vraiment, vraiment ajouter une clé primaire à votre table même si vous n'en avez pas besoin pour les performances, en particulier pour éviter des situations comme celle-ci.

3
Guran

Vous pourriez faire un

Delete <condition> limit 1

Cela supprimera seulement 1 ligne, même si plusieurs lignes correspondent à la condition. Ceci est expliqué dans le manuel officiel:

Ordre de suppression

Si l'instruction DELETE inclut une clause ORDER BY, les lignes sont supprimées dans l'ordre spécifié par la clause. Ceci est utile principalement en conjonction avec LIMIT. Par exemple, l'instruction suivante recherche les lignes correspondant à la clause WHERE, les trie par timestamp_column et supprime la première (la plus ancienne):

DELETE FROM somelog WHERE user = 'jcole'
ORDER BY timestamp_column LIMIT 1;
0
MTilsted