2010-09-08 16 views
13

J'ai un tableau de données et il y a beaucoup d'entrées en double provenant des soumissions d'utilisateur.Supprimer les lignes dupliquées en laissant la ligne la plus ancienne Seulement?

Je souhaite supprimer toutes les lignes de doublons en fonction du champ subscriberEmail, en ne conservant que la soumission d'origine. En d'autres termes, je souhaite rechercher tous les e-mails en double et supprimer ces lignes, en ne conservant que l'original.

Comment est-ce que je peux faire ceci sans permuter des tables?
Ma table contient des ID uniques pour chaque ligne.

+0

Vous devriez marquer une réponse comme "accepté" :-) – watery

Répondre

27

Puisque vous utilisez la colonne id comme un indicateur dont dossier est « original »:

delete x 
from myTable x 
join myTable z on x.subscriberEmail = z.subscriberEmail 
where x.id > z.id 

Cela laissera un enregistrement par adresse e-mail.

modifier pour ajouter:

Pour expliquer la requête ci-dessus ...

L'idée est ici pour se joindre à la table contre elle-même. Imaginez que vous avez deux copies de la table, chacune nommée quelque chose de différent. Ensuite, vous pouvez les comparer les uns aux autres et trouver l'identifiant le plus bas ou pour chaque adresse e-mail. Vous verriez alors les enregistrements en double qui ont été créés plus tard et pourraient les supprimer. (Je visualisais Excel en y réfléchissant.)

Pour effectuer cette opération sur une table, la comparer à elle-même et être capable d'identifier chaque côté, vous utilisez des alias de table. x est un alias de table. Il est affecté dans la clause from comme suit: from <table> <alias>. x peut maintenant être utilisé ailleurs dans la même requête pour faire référence à cette table en tant que raccourci. Lance la requête avec notre action et notre cible.

delete x Nous allons effectuer une requête pour sélectionner les enregistrements de plusieurs tables, et nous voulons supprimer les enregistrements qui apparaissent dans x.

Les alias sont utilisés pour désigner les deux 'instances' de la table. from myTable x join myTable z on x.subscriberEmail = z.subscriberEmail heurte la table contre lui-même où les e-mails correspondent. Sans la clause where qui suit, chaque enregistrement serait sélectionné car il pourrait être joint contre lui-même.

La clause where limite les enregistrements sélectionnés. where x.id > z.id permet à l'instance 'alias' x de contenir uniquement les enregistrements qui correspondent à des e-mails mais qui ont une valeur id supérieure. Les données que vous voulez vraiment dans le tableau, les adresses e-mail uniques (avec l'ID le plus bas) ne feront pas partie de x et ne seront pas supprimées. Les seuls enregistrements dans x seront des enregistrements en double (adresses e-mail) qui ont un id supérieur à l'enregistrement d'origine pour cette adresse e-mail.

join et où les clauses pourraient être combinées dans ce cas:

delete x 
    from myTable x 
    join myTable z 
    on x.subscriberEmail = z.subscriberEmail 
     and x.id > z.id 

Pour prévenir les doublons, pensez à faire la colonne subscriberEmail une colonne indexée UNIQUE.

+0

Hey, je ne comprends pas ce que X est dans cela, et où la date est entrée. Je pourrais employer l'identification puisqu'il y a l'identification primaire réglée pour chacun, ou la date. ID semble plus facile –

+0

Hé, ça a marché !!! J'ai changé "createdOn" en "id" et hop! haha merci - Heres le code je en PHP: mysql_query ("supprimer x de ma_table x rejoindre my_table z sur x.subscriberEmail = z.subscriberEmail où x.id> z.id") ou mourir (mysql_error ()); –

+0

Pouvez-vous expliquer comment lire ce code en anglais - Cela aide à être capable de lire quelque chose de façon logique pour comprendre la syntaxe - Aussi, maintenant comment puis-je empêcher les doublons en premier lieu? J'utilise déjà Insert IGNORE mais il n'ignore pas –

0

Si vous avez un identifiant unique pour chaque ligne, vous pouvez essayer quelque chose comme ça. Ne me demandez pas pourquoi exactement vous avez besoin de la seconde instruction select, mysql ne me laissera pas exécuter autrement. En outre, le regroupement par colonnes rend vos résultats uniques.

delete from my_table where id in (
    select id from (
    select id from my_table a group by subscriberEmail having count(*) > 1 
) b 
); 
+1

Je crois que cela supprimerait tous, pas seulement les extras. – Fosco

+0

Non ce ne serait pas. Le groupe par va grouper comme des lignes par abonnéEmail. Ainsi, un abonné avec plus d'un email sera sélectionné (comptant (*)> 1). À ce stade, vous avez à peu près un ensemble distinct d'abonnés avec plus d'un e-mail. Prenez l'identifiant de ce jeu d'enregistrements et supprimez-le. Je l'ai essayé et ça fonctionne comme un charme. –

+0

L'exécution de ce code produit une erreur "# 1064 - Vous avez une erreur dans votre syntaxe SQL, consultez le manuel correspondant à votre version du serveur MySQL pour la bonne syntaxe à utiliser près de '' à la ligne 2 - Code –

1

Que diriez-vous cela, maintenant, vous ne devez pas créer des tables temporaires en utilisant l'auto rejoint

DELETE u1 FROM users u1, users u2 WHERE u1.id < u2.id AND u1.email = u2.email 

Pour vérifier s'il y a des enregistrements en double dans le tableau

SELECT count(*) as Count, email FROM users u group by email having Count > 1