2010-03-16 10 views
2

J'ai deux tables, A et B, qui ont la même structure (environ 30+ champs). Existe-t-il un moyen court et élégant de rejoindre ces tables et de sélectionner uniquement les lignes où une ou plusieurs colonnes diffèrent? Je pourrais certainement écrire un script qui crée la requête avec tous les noms de colonnes mais peut-être qu'il existe une solution SQL uniquement.Comment sélectionner des lignes différentes dans deux tables MySQL avec la même structure?

Pour mettre une autre façon: Y at-il un court substitut à ceci:

SELECT * 
FROM table_a a 
    JOIN table_b b ON a.pkey=b.pkey 
WHERE a.col1 != b.col2 
    OR a.col2 != b.col2 
    OR a.col3 != b.col3 # .. repeat for 30 columns 

Répondre

1

Compte tenu des données, il n'y a pas de raccourci. En fait, c'est le seul solide façon de le faire. Une chose que vous devez faire attention est la comparaison correcte des valeurs NULL dans les colonnes NULL-able. La requête avec OR a tendance à être lente, ne mentionnant pas si elle est sur 30 colonnes.

Votre requête n'inclura pas non plus les enregistrements table_b qui n'ont pas d'enregistrements correspondants dans table_a. Donc, idéalement, vous utiliseriez un FULL JOIN.

Si vous avez souvent besoin d'effectuer cette opération, vous pouvez introduire une sorte de colonne de données supplémentaire qui sera mise à jour chaque fois que quelque chose changera dans la ligne. Cela pourrait être aussi simple que la colonne TIMESTAMP qui est mise à jour avec l'aide des déclencheurs UPDATE/INSERT. Ensuite, lorsque vous comparez, vous savez même quel enregistrement est le plus récent. Mais encore une fois, ce n'est pas une solution pare-balles.

0

La meilleure façon que je peux penser est de créer une table temporaire avec la même structure également, mais avec une restriction unique à travers les 30 champs que vous voulez vérifier. Insérez ensuite toutes les lignes de la table A dans la table temporaire, puis toutes les lignes de la table B dans la table temporaire ... Comme les lignes de B vont, (utilisez insert ignore) celles qui ne sont pas uniques sur au moins une colonne être laissé tomber. Le résultat sera que vous avez seulement des lignes où au moins une colonne diffère dans votre table de temp. Vous pouvez alors tout sélectionner de cela.

1

Il existe une méthode SQL standard pour ce faire (un SELECT MINUS), mais MySQL (avec de nombreux autres SGBD) ne le supporte pas.

A défaut, vous pouvez essayer ceci:

SELECT a.* FROM a NATURAL LEFT JOIN b 
    WHERE b.pkcol IS NULL 

Selon la documentation MySQL, un NATURAL JOIN rejoindra les deux tables sur toutes les colonnes portant le même nom. En filtrant les enregistrements a dans lesquels la colonne de la clé primaire b revient à NULL, vous obtenez uniquement les enregistrements a sans enregistrement de table b correspondant.

FYI: Ceci est basé sur la documentation de MySQL, pas d'expérience personnelle.

+0

Votre exemple doit être NATURAL LEFT JOIN pour pouvoir insérer des lignes de a sans correspondance dans b. – Martin

+0

... et vous devez répéter la requête, en échangeant a avec b, afin de trouver des lignes dans b sans correspondance dans a. – Martin

+0

Je vous demande pardon, c'est exact. Je l'édite maintenant. –