4. Jointures

Les jointures que nous avons utilisées pour le moment sont dites jointures internes . Si on les appelle internes , c'est qu'il doit bien en exister des externes , et c'est le cas. Avant de les voir en détail, examinons les limitations des jointures internes.

4.1. Jointure interne

Toutes les jointures que nous avons écrites jusqu'à présent sont des jointures internes. Comme on l'a vu, on peut imbriquer les jointures internes, et joindre de cette façon autant de tables qu'on le souhaite. En toute rigueur, plutôt que d'utiliser join dans nos requêtes, nous aurions dû utiliser inner join pour bien montrer le caractère "interne" de ces jointures. Cela dit, quand le mot-clé inner est omis, c'est que la jointure est interne. Les jointures internes ne répondent malheureusement pas à tous les cas que l'on rencontre. Prenons l'exemple suivant. On s'intéresse à des bateaux qui livrent des marchandises. Une première table regroupe les bateaux, et une seconde stocke les livraisons de chaque bateau. Un bateau peut livrer plusieurs fois, la relation entre la table bateau et la table livraison est donc de type 1:p. Voyons tout d'abord la structure de données que nous allons utiliser.

Exemple 65. Structure de données bateau et livraisons

-- table des bateaux
 create  table Bateaux (
   id  int  primary  key, 
   nom_bateau  varchar(32)
) ;

 -- table des livraisons
 create  table Livraisons (
   id  int  primary  key,
   id_bateau  int, 
   tonnage  int
) ;

 -- une livraison doit référencer un bateau
 alter  table Livraisons
 add  constraint FK_livraisons_bateaux
    foreign  key Livraisons(id_bateau)  references Bateaux(id) ;

Voici maintenant le contenu de nos tables.

Tableau 13. Table bateau

ID Bateau
1 Méduse
2 Altaïr
3 Perle
4 Améthyste

Voici le tonnage livré à chaque livraison, pour chaque bateau.

Tableau 14. Table livraisons

ID Bateau tonnage livré
1 120
1 110
2 220
3 190

On veut maintenant dresser le tableau du tonnage livré par bateau. Nous avons tous les éléments pour écrire cette requête.

Exemple 66. Tonnage livré par bateau - 1

select nom_bateau, sum(tonnage)
 from Livraisons
    join Bateaux  on Livraisons.id_bateau = Bateaux.id
 group  by nom_bateau
 order  by nom_bateau ;

Le résultat est le suivant.
   NOM                  SUM(TONNAGE)
   -------------------- ------------
   Altaïr                        220
   Méduse                        230
   Perle                         190
On remarque immédiatement qu'un bateau manque : l'Améthyste. Il n'a pas été sélectionné par la requête, tout simplement parce qu'il n'a rien livré, et que le prédicat Livraisons.id_bateau = Bateaux.id n'est jamais vrai pour l'Améthyste. Ce que l'on aurait aimé, c'est que l'Améthyste apparaisse dans le tableau de résultat, avec une valeur 0 pour le tonnage, ce qui n'est pas possible avec les jointures internes. C'est là que les jointures externes interviennent.

4.2. Jointure externe

Les jointures externes permettent de préserver l'une ou l'autre part de la jointure que l'on effectue. Écrivons une jointure externe pour notre table de tonnage livré.

Exemple 67. Tonnage livré par bateau - 2

select nom_bateau, sum(tonnage)
 from Livraisons
    right  outer  join Bateaux  on Livraisons.id_bateau = Bateaux.id
 group  by nom_bateau
 order  by nom_bateau ;

Le résultat cette fois-ci est le suivant.
   NOM                  SUM(TONNAGE)
   -------------------- ------------
   Altaïr                        220
   Améthyste
   Méduse                        230
   Perle                         190
Utiliser la clause right outer join plutôt que join indique au serveur que la table à droite de la jointure doit être préservée dans le résultat, c'est-à-dire que toutes ses lignes doivent apparaître, même si elles ne vérifient pas la condition de jointure. On peut de la même façon utiliser la clause left outer join, pour préserver les lignes de la table de gauche, ou full outer join pour préserver les lignes des deux tables.

4.3. Auto-jointure

Notons qu'il est parfaitement possible d'écrire la jointure d'une table sur elle-même. C'est souvent ce qui est utilisé lorsque l'on souhaite coder des structures hiérarchiques. On peut prendre l'exemple de nos marins, dont certains sont des capitaines, qui ont sous leurs ordres d'autres marins.

Exemple 68. Structure hiérarchique

-- notre table marin avec le lien de subordination
 create  table Marins (
   id  int  primary  key, 
   nom  varchar(32), 
   id_capitaine  int 
) ;

 -- un marin doit avoir un capitaine
 alter  table Marins
 add  constraint FK_marins_capitaine
    foreign  key Marins(id_capitaine)  references Marins(id) ;
	
 -- liste des marins avec le nom de leur capitaine
 select t1.nom  as nom_marin, t2.nom  as nom_capitaine
 from Marins  as t1
    join Marins  as t2  on t1.id_capitaine = t2.id
 order  by nom_marin ;

Examinons l'écriture du select qui permet d'afficher le tableau de tous les marins qui ont un capitaine, et leur capitaine. Le problème ici est que la table Marins est référencée deux fois dans la clause from : de part et d'autre de la jointure. Pour que ceci fonctionne, il faut impérativement utiliser un alias : Marins as t1 et Marins as t2. De la sorte, on peut différencier la table qui se trouve à droite de la jointure, de celle qui se trouve à gauche. On notera que la liste des champs précise dans quelle table on choisit le champ que l'on veut. Si l'on avait voulu la liste complète des marins, qu'ils aient un capitaine ou non, on aurait remplacé simplement le join par left outer join.
Introduction à SQL
Retour au blog Java le soir
Cours & Tutoriaux
Table des matières
Introduction
1. Un peu d'histoire
2. Organisation de la présentation
Un premier exemple
1. Un premier exemple
1.1. Construction d'une première table
1.2. Enregistrer quelques données
1.3. Extraire des données
2. Trier, classer, calculer
2.1. Classer des données
2.2. Trier des données
2.3. Effectuer des calculs
2.4. Mise à jour d'une valeur
3. Sélection sur plusieurs tables
3.1. Ajout du lieu de naissance
3.2. Clés primaires et clés étrangères
Organisation des données
1. Introduction
2. Bases de données, schémas et tables
2.1. Création d'une table
2.2. Création d'une colonne
2.3. Contraintes sur une table
2.4. Nommage des contraintes
2.5. Exemples de création de tables
2.6. Modification d'une table
2.7. Effacement d'une table
2.8. Remarques sur restrict et cascade
3. Types de données
3.1. Les types numériques
3.2. Les types caractère
3.3. Les types temporels
3.4. Les types binaires
3.5. Type auto-incrémental de MySQL
3.6. Type auto-généré de Derby
3.7. Séquences d'Oracle
Manipulation des données
1. Introduction
2. Extraire des données : select
2.1. Extraire des données d'une table unique
2.2. Clause where
2.3. Requêtes imbriquées
2.4. Fonctions d'agrégation, groupage
3. Supprimer des données : delete
3.1. Forme générale du delete
3.2. Effacement en cascade
3.3. Fonctionnement du delete
4. Ajouter des données : insert
4.1. Forme générale de l' insert
4.2. Copie d'une table dans une autre
5. Mettre à jour des données : update
5.1. Forme générale de l' update
5.2. Mise à jour avec une requête imbriquée
Interrogations sur plusieurs tables
1. Introduction
2. Formes normales
2.1. Première forme normale
2.2. Deuxième forme normale
2.3. Troisième forme normale
2.4. Formes normales d'ordres supérieurs
3. Relations entre éléments
3.1. Cardinalité d'une relation
3.2. Relation 1:1
3.3. Relation 1:p
3.4. Relation p:1
3.5. Relation n:p
4. Jointures
4.1. Jointure interne
4.2. Jointure externe
4.3. Auto-jointure
5. Unions
6. Vues
6.1. Création d'une vue
6.2. Exemples de vues
Transactions
1. Introduction
2. Isolation des transactions
2.1. ACIDité d'une transaction
2.2. Définition de l'isolation
3. Gestion d'une transaction
3.1. Mode auto-commit
3.2. Fixer le niveau d'isolation
3.3. Démarrer une transaction
3.4. Terminer une transaction
3.5. Remarques importantes
Index
1. Introduction
2. Manipulation d'index
2.1. Création automatique d'index
2.2. Création manuelle d'index