2011-05-04 6 views
20

J'ai une table censée conserver une trace de visiteurs dans un profil donné (ID utilisateur à paire ID utilisateur). Il s'avère que ma requête SQL était un peu éteinte et produit plusieurs paires au lieu de simples comme prévu. Avec le recul, j'aurais dû imposer une contrainte unique sur chaque paire id + id. Maintenant, comment pourrais-je nettoyer la table? Ce que je veux faire est de supprimer toutes les paires en double et n'en laisser qu'un seul.Supprimer tous les enregistrements en double, sauf un

Ainsi, par exemple changer ceci:

23515 -> 52525 date_visited 
23515 -> 52525 date_visited 
23515 -> 52525 date_visited 
12345 -> 54321 date_visited 
12345 -> 54321 date_visited 
12345 -> 54321 date_visited 
12345 -> 54321 date_visited 
23515 -> 52525 date_visited 
... 

Dans ceci:

23515 -> 52525 date_visited 
12345 -> 54321 date_visited 

Mise à jour: Voici la structure de table comme l'a demandé:

id int(10)   UNSIGNED Non  Aucun AUTO_INCREMENT 
profile_id int(10)   UNSIGNED Non  0 
visitor_id int(10)   UNSIGNED Non  0 
date_visited timestamp   Non  CURRENT_TIMESTAMP 
+0

Quelle est la structure de la table s'il vous plaît? Y a-t-il une troisième colonne à égalité de valeurs? – gbn

+0

@gbn: La structure de la table a été ajoutée (MySQL). La troisième colonne est de garder une trace de la dernière fois qu'un utilisateur a visité un profil. La structure devrait probablement être modifiée avec une contrainte sur profile_id & visitor_id. P.S: Je n'ai pas le SQL remplissant la table en ce moment mais c'est quelque chose dans le genre de 'if exists update timestamp sinon create record'. –

Répondre

36

groupe utilisation par un sous-requête :

delete from my_tab where id not in 
(select min(id) from my_tab group by profile_id, visitor_id); 

Vous avez besoin d'une sorte d'identifiant unique (ici, j'utilise id).

MISE À JOUR

Comme l'a souligné @JamesPoulson, cela provoque une erreur de syntaxe dans MySQL; la solution correcte est (comme le montre James' answer):

delete from `my_tab` where id not in 
(SELECT * FROM 
    (select min(id) from `my_tab` group by profile_id, visitor_id) AS temp_tab 
); 
+1

Excellente solution. Je n'avais pas pensé à utiliser un groupe par (expérience> connaissance). Cela affiche une clause 'Impossible de spécifier la cible dans FROM' mais il existe une solution de contournement pour cela (voir ma réponse). –

+2

Notez que cela ne fonctionne pas dans MySQL car il ne vous permet pas de modifier la table que vous utilisez dans la sélection interne: 'Code d'erreur: 1093. Vous ne pouvez pas spécifier la table cible 'my_tab' pour la mise à jour dans FROM clause' – Desty

+0

même erreur est ici. ça ne fonctionne pas – VipinS

2

Sélectionnez toutes les lignes uniques
les copier sur une nouvelle table temporaire
tronquer table originale
copie les données de la table temporaire à la table originale

C'est ce que je ferais. Je ne suis pas sûr s'il y a une requête qui ferait tout cela pour vous.

+0

L'utilisation d'une table temporaire est un bon réflexe et est réellement nécessaire. C'est probablement une approche plus adaptée s'il y a beaucoup de données. –

12

Voici la solution de Frank Schmitt avec une petite solution de contournement pour la table temporaire:

delete from `my_tab` where id not in 
(SELECT * FROM 
    (select min(id) from `my_tab` group by profile_id, visitor_id) AS temp_tab 
) 
+0

@FrankSchmitt c'est parfaitement bien :) –

1

Cela fonctionne:

With NewCTE 
AS 
(
Select *, Row_number() over(partition by ID order by ID)as RowNumber from 
table_name 
) 
Delete from NewCTE where RowNumber > 1 
Questions connexes