Les relations et la notion de jointure

1 - Introduction

Dans une base de données relationnelle, les informations sont réparties sur un grand nombre de tables.
Il est donc fréquent qu'une requête porte sur deux tables (ou plus), liées par une (ou plusieurs) relation(s).
La notion de jointure précise comment fonctionnent cette (ou ces) relation(s) lors de l'exécution de la requête.
Comme pour les autres chapitres de ce tutoriel (ou tutorial, ou cours en ligne), nous utilisons le SGBD Access comme support pratique.
Pour bâtir un exemple, nous faisons appel aux deux tables "Personnes" et "Communes" dont nous nous sommes déjà servis au chapitre 4.
Nous remplissons ces deux tables comme le montre la figure ci-dessous.
Précisons que le champ "Commune" de la table "Personnes" n'a pas été rendu obligatoire (le Null est autorisé), si bien qu'il peut arriver qu'une commune ne soit pas attribuée à une personne, comme c'est le cas pour Jeanne Dupont.
Les deux tables sont liées par une relation, assurée via un code masqué. Cette relation apparaît dans la fenêtre "Relations", comme le montre la figure ci-dessous.
Relation entre les deux tables

2 - La relation

Si nous ajoutons les deux tables précitées à la fenêtre de création d'une requête, nous constatons que la relation qui les lie est toujours présente.
Dans la fenêtre de création d'une requête, nous pouvons supprimer cette relation. La procédure est identique à celle pratiquée dans la fenêtre "Relations" : nous effectuons un clic droit sur la relation, et nous choisissons "Supprimer". Nous fermons la fenêtre de création de la requête, et nous enregistrons cette dernière.
Si nous ouvrons la fenêtre "Relations", nous constatons que la relation qui lie les deux tables existe toujours. Cette relation est en quelque sorte une propriété des deux tables.
La suppression que nous avons effectuée est liée à une requête particulière. Elle n'a d'effet que lors de l'exécution de la requête. Ce n'est pas une propriété des deux tables, mais une propriété de la requête.
En conclusion, les opérations que nous effectuons sur les relations (création, suppression, modification des propriétés) ont un effet :
  • permanent lorsqu'elles sont effectuées dans la fenêtre "Relations" ;
  • éphémère lorsqu'elles sont effectuées dans la fenêtre de création d'une requête particulière.
Remarque : même s'il n'existe pas de relation entre deux tables, le SGBD Access en crée une automatiquement lorsque vous ajoutez ces deux tables à la fenêtre de création d'une requête, à condition que ces tables aient chacune un champ du même nom et du même type de données, et qu'un des deux champs possède une clé primaire.

3 - Le produit vectoriel

Nous rouvrons la requête précédente en mode "Modification".
Nous vérifions qu'aucune relation n'apparaît entre les deux tables.
Dans la grille, nous introduisons les champs "Nom" et "Prénom" de la première table, et les champs "Commune" et "Code postal" de la seconde.
La feuille de données résultante contient 20 lignes ! Que s'est-il passé ?

Le SGBD a associé chaque ligne de la première table (il y en a 4) à chaque ligne de la seconde (il y en a 5). On dit qu'il a effectué le produit vectoriel des deux tables.
L'absence de relation fait que le SGBD ne sait pas comment il doit associer les lignes des deux tables ; de ce fait, il réalise toutes les combinaisons possibles.
Attention : Le fait que le produit vectoriel peut nous conduire à créer des tables gigantesques : le produit de deux tables contenant chacune 1.000 enregistrements est une table possédant 1 million de lignes !

En pratique, on n'utilise pas le produit vectoriel, sauf dans des cas très rares, comme par exemple pour réunir dans une seule table des comptages isolés.
Ces derniers se présentent en effet sous forme de tables à une seule ligne, et l'on peut en faire le produit vectoriel sans risque, car le résultat est alors une table à une seule ligne.

4 - La jointure interne

Dans la fenêtre de création de la requête, nous rétablissons la relation entre les deux tables. Cette fois, la feuille de données résultante ne contient plus que 3 lignes, comme le montre la figure ci-dessous.
Nom Prénom Commune Code postal
Truc Jean Grenoble 38000
Chose Pierre Nancy 54000
Machin Noémie Uriage 38410

Nous constatons que ne figurent dans la table résultante que les enregistrements qui sont présents dans les deux tables. La personne Dupont Jeanne, dont la commune n'est pas précisée, est absente du résultat. Les villes Grenoble (38001) et SMH, auxquelles ne correspond aucune personne, sont également absente. Le SGBD a traité la relation entre les deux tables comme une jointure interne.
Effectuons un clic droit sur la relation, et sélectionnons "Propriétés de la jointure". La fenêtre du même nom s'affiche ; elle se présente comme le montre la figure ci-dessous.
Bien que le terme ne soit pas présent, l'option 1 de la fenêtre correspond effectivement à la jointure interne.
Jointure interne
Remarque : dans la requête précédente, le champ "Commune" est issu de la table "Communes". S'il provenait de la table "Personnes", le résultat s'afficherait de la même façon. C'est seulement en exportant la table que l'on peut s'apercevoir que dans le second cas, le champ contient un code au lieu d'un nom de commune.

5 - La jointure gauche

La fenêtre "Propriétés de la jointure", représentée ci-dessus, nous fournit deux autres options.
Nous activons le bouton 2 et nous validons par "OK". La requête se présente maintenant comme le montre la figure ci-dessous.
Nous avons affaire à une jointure gauche.
Pour le signaler, la liaison prend la forme d'une flèche... dirigée vers la droite.

Jointure gauche
Si nous basculons en mode feuille de données, nous obtenons le résultat suivant :
Nom Prénom Commune Code postal
Truc Jean Grenoble 38000
Chose Pierre Nancy 54000
Machin Noémie Uriage 38410
Dupont Jeanne


Cette fois, le SGBD a conservé tous les enregistrements de la table "Personnes", et il leur a associé les enregistrements disponibles dans la table "Communes". 
Comme nous n'avons pas précisé de critère de sélection, tous ces enregistrements ont été conservés.

6 - La jointure droite

Dans la fenêtre "Propriétés de la jointure", nous activons le bouton 3 et nous validons par "OK".
Nous avons maintenant affaire à une jointure droite.
Pour le signaler, la liaison prend la forme d'une flèche... dirigée vers la gauche.
Si nous basculons en mode feuille de données, nous obtenons le résultat suivant :
Nom Prénom Commune Code postal
Truc Jean Grenoble 38000


Grenoble 38001
Chose Pierre Nancy 54000
Machin Noémie Uriage 38410


SMH 38402

Cette fois, le SGBD a conservé tous les enregistrements de la table "Communes", et il leur a associé les enregistrements disponibles dans la table "Personnes". 
Comme nous n'avons pas précisé de critère de sélection, tous ces enregistrements ont été conservés.
Conclusion : le résultat d'une requête multi-table dépend du type de jointure choisi. Par défaut, c'est la jointure interne qui s'applique.

7 - La requête de non correspondance

La requête de non correspondance constitue une application importante de la notion de jointure. Elle met en jeu deux tables ayant en commun un champ possédant le même type de données, et doté des mêmes propriétés (mais pas forcément du même nom).
La requête de non-correspondance ne conserve un enregistrement de la première table que si le contenu du champ n'est pas présent dans la seconde table.
Les deux tables n'ont pas besoin d'être liées au préalable par une relation, cette dernière sera créée en même temps que la requête.
Pour construire un exemple simple, nous créons deux tables à un seul champ, contenant des prénoms, et intitulées "Prénoms1" et "Prénoms2". Les tables se présentent ainsi :
Prénom
Paul
Jean
Marie
Henri
Claude
     
Prénom
Henri
Patrick
Paul


"Prénoms1" "Prénoms2"

Nous recherchons les prénoms de la première table qui sont absents de la seconde. 
Pour ce faire, nous devons passer en revue tous les prénoms de la première table, et regarder s'ils sont ou non dans la seconde. 
Pour créer la requête correspondante, nous songeons donc à utiliser une jointure gauche.
Pour bien comprendre ce qui se passe, nous pouvons décomposer en deux temps le fonctionnement de la requête. D'abord, le SGBD sélectionne tous les prénoms de la première table, et leur associe les prénoms de la seconde table quand il sont identiques. Le résultat de cette première étape peut être représenté ainsi :
Prénom1 Prénom2
Paul Paul
Jean
Marie
Henri Henri
Claude

Il faut maintenant que le SGBD applique un critère de sélection, pour ne conserver que les lignes dont la deuxième colonne est vide. Nous plaçons donc le critère "Est Null" dans la colonne relative au champ "Prénom" de la seconde table.
En définitive, nous obtenons la requête représentée sur la figure ci-dessous (remarquez la flèche qui traduit la jointure gauche). Nous avons supprimé l'affichage de la seconde colonne, car il conduirait à créer une colonne vide dans la feuille de données résultante.
Requête de non-correspondance
Si nous basculons en mode feuille de données, nous obtenons le résultat suivant :
Prénom
Jean
Marie
Claude

Il est indispensable, dans un requête de non correspondance, de ne pas se tromper sur le type de jointure à utiliser. Ainsi, si nous choisissons la jointure interne (par défaut), le SGBD ne sélectionne que les prénoms qui sont simultanément présents dans les deux tables. Le résultat de cette étape intermédiaire est représenté ci-dessous :
Prénom1 Prénom2
Paul Paul
Henri Henri

Lorsque nous appliquons le critère "Est Null" à la deuxième colonne,  le SGBD ne conserve que les lignes pour lesquelles la deuxième colonne est vide. Comme il n'y en a pas, la feuille de données résultante ne contient aucun enregistrement -- ce que l'expérience confirme.
Si nous utilisons la jointure droite, le SGBD sélectionne tous les prénoms de la seconde table, et seulement ceux de la première table qui se trouvent dans la seconde. Cette étape intermédiaire peut être représentée ainsi :
Prénom1 Prénom2
Paul Paul
Henri Henri

Patrick

Puis le SGBD élimine les lignes pour lesquelles la seconde colonne est vide. Comme il n'y en a pas, la feuille de données résultante ne contient aucun enregistrement -- ce que l'expérience confirme.
Si le raisonnement relatif à la requête de non correspondance vous paraît ardu, ne vous inquiétez pas : vous n'êtes pas le seul. C'est la raison pour laquelle Microsoft a créé un assistant pour ce type de recherche. Vous le trouverez dans la fenêtre "Base de données", l'objet "Requêtes" étant sélectionné. Vous cliquez sur l'icône "Nouveau", et vous sélectionnez "Assistant Requête de non-correspondance".

8 - La requête de correspondance

La requête de correspondance est en quelque sorte le complément de la précédente. Elle met en jeu deux tables ayant en commun un champ possédant le même type de données, et doté des mêmes propriétés (mais pas forcément du même nom). Elle ne conserve un enregistrement de la première table que si le contenu du champ est présent dans la seconde table. La requête de correspondance constitue elle aussi une application courante de la notion de jointure. Comme précédemment, les deux tables n'ont pas besoin d'être liées au préalable par une relation, cette dernière étant créée en même temps que la requête.
Cette fois, nous recherchons les prénoms de la première table qui sont présents dans la seconde. Pour créer la requête correspondante, il nous faut utiliser une jointure interne. Cela suffit, il n'est pas utile de préciser un critère. Nous obtenons ainsi la requête représentée sur la figure ci-dessous.
Requête de concordance
Si nous basculons en mode feuille de données, nous obtenons le résultat suivant, complémentaire de celui obtenu avec la requête de non correspondance :
Prénom
Henri
Paul
Exercez-vous à prévoir ce qui se passe si vous vous trompez de jointure, et vérifiez si l'expérience confirme vos prédictions.
La requête de correspondance étant plus facile à créer que la requête de non-correspondance, l'éditeur d'Access n'a pas prévu d'assistant pour aider à la créer. Cependant, vous pouvez utiliser l'assistant précédent, et changer simplement la condition "Est Null" par son contraire "Est Pas Null". C'est inutilement compliqué, mais cela marche.

9 - Conclusion

La notion de jointure joue un rôle important dans les requêtes multi-tables, en particulier dans les requêtes de correspondance et de non correspondance.
Si l'opérateur ne précise pas le type de jointure, c'est la jointure interne que le SGBD applique par défaut.

Aucun commentaire:

Enregistrer un commentaire