2010-12-15 9 views
3

J'ai une table structurée comme suit:Vérifiez les doublons dans une base de données et de les supprimer

table(A, B) 

Ils sont les deux clés primaires et ils sont nécessaires pour connecter deux entrées dans une autre table (ils simbolize une amitié entre utilisateurs).

Je dois vérifier la table et, si (A, B) existe, supprimer un éventuel (B, A) (ou vice versa).
Étant donné que la base de données est énorme, je ne peux pas le faire manuellement pour chaque entrée à chaque fois.

Bien sûr, j'ai programmé le script qui peuplait la base de données pour vérifier cette situation et l'éviter, mais nous avons utilisé ce script sur 8 PC différents et donc les différents dumps peuvent avoir des "reverse duplicates".

+0

Voulez-vous nettoyer une table de base de données existante ou l'empêcher à l'avenir? Sûrement un déclencheur sur insertion/mise à jour pourrait rapidement valider si l'enregistrement inverse est présent? Dans ce cas, vous devez simplement exécuter un exercice unique de nettoyage des données existantes (qui ne doit pas être exécuté rapidement) –

+0

Vous ne pouvez pas déclarer les clés dans les deux sens? Comme dans, UNIQUE (a, b) et UNIQUE (b, a)? Ensuite, la base de données elle-même appliquerait vos contraintes sans même avoir besoin de déclencheurs. – Borealid

+1

Je sais qu'il est trop tard maintenant, mais ce problème aurait pu être évité par l'application: A et B sont généralement ids et votre application ne devrait enregistrer les paires dans la table où A Robert

Répondre

1

Le problème est survenu parce que la relation que vous essayez de décrire est symétrique - mais le schéma modélise une association asymétrique. Le droit de modéliser le problème consisterait à maintenir une table de relations - puis d'avoir une table reliant les utilisateurs aux relations, par ex.

relationship: 
    id auto_increment 

related: 
    r_id foreign key references relationship.id 
    u_id foreign key references user.id 
    primary key (r_id, u_id) 

Mais pour nettoyer les données existantes ... une approche évidente serait ...

DELETE FROM yourtable d 
WHERE A>B AND EXISTS (
    SELECT 1 
    FROM yourtable r 
    WHERE r.A=d.B 
    AND r.B =d.A 
) 

Cependant, si je me souviens bien MySQL n'aime pas l'aide d'un sous-sélection dans une suppression qui fait référence à la même table que la suppression. Alors ....

SELECT d.A,d.B 
INTO dups 
FROM yourtable d, yourtable r 
WHERE d.A>d.B 
AND r.A=d.B 
AND r.B =d.A; 

alors ....

DELETE FROM yourtable 
WHERE EXISTS (
SELECT 1 FROM dups 
WHERE dups.A=yourtable.A 
AND dups.B=yourtable.B 
) 

Je ne sais pas si le prédicat poussé va encore causer un problème, donc si cela ne fonctionne pas ....

DELETE FROM yourtable 
WHERE CONCAT(A, '/', B) IN (
SELECT CONCAT(A, '/' B) FROM dups 
) 
+0

Cela a fonctionné parfaitement! Juste une note: le sintax correct est INSERT INTO ... SELECT ... FROM. Merci! – Gurzo

Questions connexes