mardi 20 mars 2012

Les jointures INNER JOIN, LEFT, RIGHT et FULL OUTER JOIN

Souvent, dans une base de données, les données sont reparties entre plusieurs tables. On peut très bien imaginer une table contenant un clé étrangère vers une autre table. A ce moment là, comment faire pour récupérer les informations de cette table et de la table vers laquelle pointe la clé étrangère en une seule requête ? Si vous ne voyez pas ce que je veux dire, vous allez tout de suite comprendre. Imaginez ce schéma de base de données.

Image


Nous allons partir du fait que ces tables contiennent déjà les données suivantes :

VOITURES



Image


COULEURS



Image


PERSONNES



Image


PERSONNE_VOITURE



Image


Nous allons voir maintenant des techniques permettant en une requête de récupérer des données qu'il serait impossible de récupérer facilement avec un SELECT.

Jointure interne



Nous allons donc voir ici la plus simple jointure qu'il existe : la jointure interne. Imaginez un formulaire de recherche. Dans un champ, on rentre un identifiant et à partir de cet identifiant, la personne dont l'identifiant correspond à la valeur de ce champ sera récupéré et ses informations seront affichées. Seulement, nous voulons également savoir quelle voiture il possède ainsi que la couleur de celle-ci. Avec juste un SELECT, cela serait très compliqué (il faudrait utiliser IN par exemple avec des SELECTimbriqués).

Tout d'abord, comment fonctionne une jointure interne ? En fait, tout part d'une requête SELECT. Grâce à celle-ci, nous allons récupérer les informations de la personnes. Juste les informations se trouvant dans la table PERSONNES. Une fois ces infos récupérées, nous allons JOINDRE à ce résultat une table de la base de données. Nous devons spécifier grâce à quel critère la jointure sera effectuée. Généralement, cela se fait à base de clé primaire/étrangère. Par exemple, ici, nous allons joindre la partie de la table PERSONNE_VOITURE pour laquelle le champ PERSONNE_ID de cette table correspond au champID_PERSONNE de la table PERSONNE. Etant donné qu'une seule occurence de cette valeur est présente, il n'y aura que la ligne correspondant dans la table PERSONNE_VOITURE qui sera joint. Bon ok, vous n'avez rien compris, j'vous comprend, même moi je me perd dans mes explications. Voyons cela grâce à un exemple.

Tout d'abord, voici la syntaxe d'une jointure interne. Nous l'expliquerons sur base de l'exemple :

  1. INNER JOIN table  
  2. [ON champ1=champ2 [{AND | OR} champ3=champ4,... ]]  


Voyons comment se servir de cela grâce à un exemple. Imaginez donc tout d'abord une simple requête permettant de retrouver une personne sur base de son identifiant. La requête serait donc la suivante :

  1. SELECT ID_PERSONNE, NOM, PRENOM, AGE  
  2. FROM PERSONNES  
  3. WHERE ID_PERSONNE = 3  


Nous allons imaginer pour l'instant que la personne recherchée sera celle dont l'identifiant correspond à 3. Voici donc le résultat renvoyé par cette requête :

Image


Jusque là, tout est normal. Nous allons maintenant joindre la table PERSONNE_VOITURE sans condition pour voir un petit peu ce que cela fait. Tapez donc :

  1. SELECT ID_PERSONNE, NOM, PRENOM, AGE, PERSONNE_ID, VOITURE_ID, COULEUR_ID  
  2. FROM PERSONNES  
  3. INNER JOIN PERSONNE_VOITURE  
  4. WHERE ID_PERSONNE = 3  


Le résultat renvoyé par cette requête est le suivant :

Image


Ce résultat est logique. Comme vous le voyez, nous commençons par sélectionner plus de champs. En effet, étant donné que nous joignons la table PERSONNE_VOITURE à la requête, les champs de cette table pourront être indiqués dans la liste des champs à sélectionner par le SELECT. Comme vous le voyez, la requête reste la même à l'exception de l'INNER JOIN. Mais si la requête reste la même, pourquoi y a-t-il 4 résultats au lieu de 1 ?

La réponse est simple. La table PERSONNE_VOITURE contient 4 enregistrements et la requête sans le INNER JOIN renvoie 1 seul résultat. Pour afficher le résultat de ces deux requêtes ensemble, il y aura 4 résultats. Si nous disons que le SELECT sans l'INNER JOIN est la requête S et que l'INNER JOIN est la requête I, le résultat renvoyé est le suivant :

Enregistrement de S suivi du premier enregistrement de I
Enregistrement de S suivi du deuxième enregistrement de I
Enregistrement de S suivi du troisième enregistrement de I
Enregistrement de S suivi du quatrième enregistrement de I

Les résultats sont donc combinés entre eux pour qu'ils apparaissent tous. Bien évidemment ici, tout ne nous intèresse pas. Regardez par exemple la première ligne. le champ PERSONNE_ID vaut 2 et non 3, c'est donc un enregistrement qui concerne la personne 2, cet enregistrement n'a donc rien à faire dans le résultat. Il est néanmoins présent car nous n'avons pas stipulé de condition à la jointure. Ce type de condition s'indique grâce au mot clé ON juste après la jointure. Tapez par exemple cette requête :

  1. SELECT ID_PERSONNE, NOM, PRENOM, AGE, PERSONNE_ID, VOITURE_ID, COULEUR_ID  
  2. FROM PERSONNES  
  3. INNER JOIN PERSONNE_VOITURE  
  4. ON ID_PERSONNE = PERSONNE_ID  
  5. WHERE ID_PERSONNE = 3   


Le ON fonctionne comme le WHERE, il est donc possible de préciser plusieurs conditions séparées par des AND ou OR. Ici, nous joignons encore une fois la table PERSONNE_VOITURE à la sélection, mais nous ne joignons que les enregistrements où le champ ID_PERSONNE de la table PERSONNES est le même que le champ PERSONNE_ID de la tablePERSONNE_VOITURE. Ainsi, tous les enregistrements joints concernent la personne ayant l'identifiant 3. La preuve :

Image


Nous avançons bien, mais ce n'est pas fini. Effectivement, maintenant que nous avons l'identifiant des voitures que la personne possède ainsi que l'identifiant de leur couleur, il serait plus agréable de récupérer leur intitulé. Il suffit simplement de faire deux autres INNER JOIN. Voyons d'abord celui pour la voiture :

  1. SELECT ID_PERSONNE, NOM, PRENOM, AGE, PERSONNE_ID, MARQUE, COULEUR_ID  
  2. FROM PERSONNES  
  3. INNER JOIN PERSONNE_VOITURE  
  4. ON ID_PERSONNE = PERSONNE_ID  
  5. INNER JOIN VOITURES  
  6. ON ID_VOITURE = VOITURE_ID  
  7. WHERE ID_PERSONNE = 3   


Le résultat renvoyé par cette requête est le suivant :

Image


Comme vous le voyez, cette fois, c'est la marque de la voiture et non plus l'identifiant qui apparaît. C'est réalisé très simplement. On commence par joindre la table VOITURES au résultat obtenu précédemment mais comme nous ne voulons que les voitures appartenant à la personne en question, on pose une condition grâce au ON qui ne joindra aux lignes du résultats QUE les liens dont l'identifiant récupéré dans la table PERSONNE_VOITURE sera le même que dans le champ ID_VOITURE de la tableVOITURES.

Modifions maintenant une dernière fois la requête pour récupérer uniquement les champs qui nous interesse mais également pour récupérer l'intitulé de la couleur de la voiture :

  1. SELECT NOM, PRENOM, AGE, MARQUE, COULEUR  
  2. FROM PERSONNES  
  3. INNER JOIN PERSONNE_VOITURE  
  4. ON ID_PERSONNE = PERSONNE_ID  
  5. INNER JOIN VOITURES  
  6. ON ID_VOITURE = VOITURE_ID  
  7. INNER JOIN COULEURS  
  8. ON ID_COULEUR = COULEUR_ID  
  9. WHERE ID_PERSONNE = 3   


L'exécution de cette requête produirait le résultat suivant :

Image


Youhou o/ C'est ce qu'on voulait. La première différence avec cette requête et les précédentes est le fait que nous ne sélectionnons plus que les champs qui nous interessent. Inutile de sélectionner le champ PERSONNE_ID vu qu'on le connait car c'est sur cela que porte la condition après le WHERE. Ensuite, nous avons à nouveau joint une nouvelle table. Cette fois, c'est COULEURS que nous joignons et encore une fois nous joignons cette table selon une condition comme quoi le champID_COULEUR de cette table doit être égal au champ COULEUR_ID récupéré de la table PERSONNE_VOITURE.

Vous allez voir que les jointures internes sont bien mais souffrent d'un problème que les jointures externes peuvent facilement régler. Vous allez voir cela tout de suite.

Jointures externes



Considérez la requête établie précédemment :

  1. SELECT NOM, PRENOM, AGE, MARQUE, COULEUR  
  2. FROM PERSONNES  
  3. INNER JOIN PERSONNE_VOITURE  
  4. ON ID_PERSONNE = PERSONNE_ID  
  5. INNER JOIN VOITURES  
  6. ON ID_VOITURE = VOITURE_ID  
  7. INNER JOIN COULEURS  
  8. ON ID_COULEUR = COULEUR_ID  
  9. WHERE ID_PERSONNE = 3   


Nous avons vu qu'elle fonctionnait très bien avec la personne dont l'identifiant valait 3. Essayez maintenant d'exécuter cette requête avec l'identifiant 1. Si vous le faites, vous verrez qu'aucun résultat n'est renvoyé. C'est étrange car même si la personne 1 ne possède pas de voiture, cette personne existe. C'est en fait une réaction normale. Effectivement, lorsque les INNER JOINsont évalués, les tables sont jointes et ce, généralement sous condition. Si une condition n'est pas respectée, donc qu'aucun ligne de la table distante ne peut être jointe, aucun résultat ne sera renvoyé. Ici, quand la première jointure va être exécutée, donc celle qui joint PERSONNES à PERSONNE_VOITURE, aucune ligne ne pourra être jointe. Effectivement, aucune ligne de la tablePERSONNE_VOITURE ne contient d'enregistrement avec le champ PERSONNE_ID valant 1. Aucune ligne ne sera donc jointe et aucune ligne ne sera renvoyée en résultat.

Sachez qu'il existe trois types de jointures externes. Les gauches, les complètes et les droites. La différence n'est pas énorme. Dans le cas des jointures externe gauche, on rajoute les lignes de la table de gauche qui n'ont pas été prises en compte. Dans le cas d'une jointure droite, ce sont les lignes de la table de droite qui n'ont pas été prises en compte qui sont rajoutées. Enfin, les jointures externes complètes ajoutent les lignes de la table qui n'ont pas été prises en compte de gauche et de celle de droite. La table de gauche est celle qui apparaît dans la requête SQL AVANT le mot clé de jointure, tandis que celle de droite est celle qui apparaît APRES le mot clé de jointure.

La syntaxe d'une jointure externe est la suivante :

  1. LEFT | RIGHT | FULL OUTER JOIN table_droite  
  2. ON condition   


Vous devez choisir entre LEFT (gauche), FULL (complète) ou RIGHT (droite). Le mot clé OUTER n'est pas obligatoire mais bon, nous vous conseillons de le mettre pour la clarté de votre requête. Nous allons maintenant modifier la requête précédente pour voir un petit peu le fonctionnement des jointures externes. Remplacez donc tout les INNER par des LEFT OUTER pour donner ceci :

  1. SELECT NOM, PRENOM, AGE, MARQUE, COULEUR  
  2. FROM PERSONNES  
  3. LEFT OUTER JOIN PERSONNE_VOITURE  
  4. ON ID_PERSONNE = PERSONNE_ID  
  5. LEFT OUTER JOIN VOITURES  
  6. ON ID_VOITURE = VOITURE_ID  
  7. LEFT OUTER JOIN COULEURS  
  8. ON ID_COULEUR = COULEUR_ID  
  9. WHERE ID_PERSONNE = 1   


L'exécution de cette requête donnera :

Image


Comme vous le voyez, il y a du mieux. Nous avons maintenant récupérer une ligne avec des valeurs nulles. Ce résultat est logique. En effet, la première jointure joint la table PERSONNES et PERSONNE_VOITURE, mais la table PERSONNE_VOITUREne contient aucun enregistrement avec le champ PERSONNE_ID contenant 1, une jointure interne échouerait donc. La jointure externe, elle, va joindre une ligne de résultat contenant NULL comme valeur pour PERSONNE_ID et VOITURE_ID. Les deux jointures externes suivantes vont procéder de la même façon car elles vont essayer de joindre des tables dans leqsuelles des champs vaudront NULL. En effet, VOITURE_ID valant NULL après la première jointure, la requête va essayer de joindre la tableVOITURES avec la ligne qui contient NULL dans le champ ID_VOITURE. Il n'existe pas d'enregistrement de ce type. C'est donc la valeur NULL qui sera jointe. Il en ira de même avec la table COULEURS.

Nous pourrions voir dans ce cours un tas d'autres exemples, mais une bonne compréhension du SQL passe par la répetition. En effet, vous devez faire et refaire plein de commandes différentes et analyser les résultats pour bien comprendre les comportement des mots clé que vous utilisez. Je vous conseille donc de faire le plus de jointures possibles pour bien comprendre leur fonctionnement car c'est vraiment très importante et utile. Il reste d'autres types de jointure, mais je ne les connais pas. Le cours sera donc mis à jour une fois que j'aurais appris leur fonctionnement.

Aucun commentaire:

Enregistrer un commentaire