141 votes

Quelle est la meilleure façon de faire une jointure sur la même table deux fois ?

C'est un peu compliqué, mais j'ai deux tableaux. Disons que la structure est quelque chose comme ceci :

*Table1*
ID
PhoneNumber1
PhoneNumber2

*Table2*
PhoneNumber
SomeOtherField

Les tables peuvent être jointes sur la base de Table1.PhoneNumber1 -> Table2.PhoneNumber, ou Table1.PhoneNumber2 -> Table2.PhoneNumber.

Je souhaite maintenant obtenir un jeu de résultats contenant PhoneNumber1, SomeOtherField correspondant à PhoneNumber1, PhoneNumber2 et SomeOtherField correspondant à PhoneNumber2.

J'ai pensé à deux façons de le faire - soit en joignant deux fois la table, soit en la joignant une fois avec un OR dans la clause ON.

Méthode 1 :

SELECT t1.PhoneNumber1, t1.PhoneNumber2, 
   t2.SomeOtherFieldForPhone1, t3.someOtherFieldForPhone2
FROM Table1 t1
INNER JOIN Table2 t2
   ON t2.PhoneNumber = t1.PhoneNumber1
INNER JOIN Table2 t3
   ON t3.PhoneNumber = t1.PhoneNumber2

Cela semble fonctionner.

Méthode 2 :

Pour avoir en quelque sorte une requête qui ressemble à ceci -

SELECT ...
FROM Table1
INNER JOIN Table2 
   ON Table1.PhoneNumber1 = Table2.PhoneNumber OR
      Table1.PhoneNumber2 = Table2.PhoneNumber

Je n'ai pas encore réussi à faire fonctionner ce système et je ne sais pas s'il existe un moyen de le faire.

Quelle est la meilleure façon d'y parvenir ? Aucune de ces méthodes ne semble simple ou intuitive... Existe-t-il une méthode plus directe ? Comment cette exigence est-elle généralement mise en œuvre ?

179voto

Paul Sasik Points 37766

Tout d'abord, j'essaierais de remanier ces tables pour éviter d'utiliser les numéros de téléphone comme clés naturelles. Je ne suis pas un fan des clés naturelles et ceci est un excellent exemple. Les clés naturelles, en particulier les numéros de téléphone, peuvent changer, et ce fréquemment. La mise à jour de votre base de données lorsque ce changement se produit sera un ÉNORME mal de tête, source d'erreurs. *

Méthode 1 tel que vous le décrivez est votre meilleur atout. Elle semble un peu laconique en raison du schéma de dénomination et des alias courts, mais... l'alias est votre ami lorsqu'il s'agit de joindre plusieurs fois la même table ou d'utiliser des sous-requêtes, etc.

Je ferais juste un peu de ménage :

SELECT t.PhoneNumber1, t.PhoneNumber2, 
   t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2
FROM Table1 t
JOIN Table2 t1 ON t1.PhoneNumber = t.PhoneNumber1
JOIN Table2 t2 ON t2.PhoneNumber = t.PhoneNumber2

Ce que j'ai fait :

  • Il n'est pas nécessaire de spécifier INNER - c'est implicite du fait que vous ne spécifiez pas LEFT ou RIGHT.
  • Ne pas n-suffixer votre table de recherche primaire
  • N-Suffixez les alias de table que vous utiliserez plusieurs fois afin de les rendre évidents.

*Une façon pour les administrateurs de bases de données d'éviter les problèmes de mise à jour des clés naturelles est de ne pas spécifier les clés primaires et les contraintes de clés étrangères, ce qui aggrave encore les problèmes liés à une mauvaise conception de la base de données. J'ai vu cela plus souvent qu'autrement.

8voto

HLGEM Points 54641

La première solution est bonne, sauf si Phone1 ou (plus probablement) phone2 peut être nul. Dans ce cas, vous devez utiliser une jointure gauche au lieu d'une jointure interne.

Il est généralement mauvais signe d'avoir une table avec deux champs de numéro de téléphone. Cela signifie généralement que la conception de votre base de données est défectueuse.

5voto

Pointy Points 172438

Vous pouvez utiliser UNION pour combiner deux jointures :

SELECT Table1.PhoneNumber1 as PhoneNumber, Table2.SomeOtherField as OtherField
  FROM Table1
  JOIN Table2
    ON Table1.PhoneNumber1 = Table2.PhoneNumber
 UNION
SELECT Table1.PhoneNumber2 as PhoneNumber, Table2.SomeOtherField as OtherField
  FROM Table1
  JOIN Table2
    ON Table1.PhoneNumber2 = Table2.PhoneNumber

3voto

Nelson Rothermel Points 3538

La première méthode est la bonne et répondra à vos besoins. Cependant, avec les jointures internes, vous ne sélectionnerez que les lignes de Table1 si les deux numéros de téléphone existent dans Table2 . Il est possible que vous souhaitiez faire une LEFT JOIN de sorte que toutes les lignes de Table1 sont sélectionnés. Si les numéros de téléphone ne correspondent pas, l'option SomeOtherField seraient nulles. Si vous voulez être sûr d'avoir au moins un numéro de téléphone correspondant, vous pouvez alors procéder comme suit WHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

La deuxième méthode pourrait poser un problème : que se passe-t-il si Table2 a à la fois PhoneNumber1 y PhoneNumber2 ? Quelle ligne sera sélectionnée ? En fonction de vos données, des clés étrangères, etc., cela peut ou non poser un problème.

3voto

F1iX Points 121

Mon problème était de afficher l'enregistrement même s'il n'y a pas de numéro de téléphone ou s'il n'y en a qu'un seul (carnet d'adresses complet). J'ai donc utilisé un JOINT DE GAUCHE qui prend tous les enregistrements de gauche, même s'il n'existe pas de correspondant à droite. Pour moi, cela fonctionne en Microsoft Access SQL (il faut des parenthèses !)

SELECT t.PhoneNumber1, t.PhoneNumber2, t.PhoneNumber3
   t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2, t3.someOtherFieldForPhone3
FROM 
(
 (
  Table1 AS t LEFT JOIN Table2 AS t3 ON t.PhoneNumber3 = t3.PhoneNumber
 )
 LEFT JOIN Table2 AS t2 ON t.PhoneNumber2 = t2.PhoneNumber
)
LEFT JOIN Table2 AS t1 ON t.PhoneNumber1 = t1.PhoneNumber;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X