Niveau 10 : LEFT JOIN et jointures multiples
Mis à jour le
Intermédiaire · niveau 10 sur 20. Objectif : Garder les lignes sans correspondance, enchaîner plusieurs jointures et joindre une table à elle-même.
Notions : LEFT JOIN lignes sans correspondance plusieurs JOIN auto-jointure
Leçon
JOIN fait disparaître les lignes sans correspondance. Or ce sont souvent elles qui comptent : les clients qui n'ont jamais commandé, les livres jamais empruntés. LEFT JOIN les garde.
LEFT JOIN garde toutes les lignes de la table de gauche, celle écrite dans le FROM. Quand une ligne a une correspondance, on obtient la même chose qu'avec JOIN. Quand elle n'en a pas, elle est quand même gardée, et toutes les colonnes de la table de droite valent NULL. FROM directors d LEFT JOIN movies m … garde ainsi Sara Diaz, avec un titre NULL.
Pour trouver les « orphelins », on fait un LEFT JOIN puis WHERE droite.id IS NULL : seules restent les lignes de gauche sans correspondance. Pour compter, utilise COUNT(droite.id), qui vaut 0 pour une ligne sans correspondance ; COUNT(*) compterait 1, car la ligne existe bien dans le résultat.
Piège classique : une condition sur la table de droite placée dans le WHERE. Le WHERE est exécuté après la jointure ; pour une ligne sans correspondance, la colonne de droite vaut NULL, le test échoue et la ligne disparaît, comme avec un JOIN ordinaire. Pour filtrer la table de droite sans perdre les lignes de gauche, mets la condition dans le ON : LEFT JOIN orders o ON o.customer_id = c.id AND o.status = 'shipped'. Le défi 10.5 te fait rencontrer ce piège.
On peut enchaîner autant de jointures que nécessaire, chacune avec son ON. Une table peut aussi être jointe à elle-même : c'est une auto-jointure. Dans staff, manager_id pointe vers l'id d'un autre employé. FROM staff e LEFT JOIN staff m ON m.id = e.manager_id lit la table deux fois sous deux alias : e pour l'employé, m pour son manager. m.name donne alors le nom du manager, et le LEFT JOIN garde Alice, qui n'en a pas.
Syntaxe
SELECT …
FROM a
LEFT JOIN b ON b.a_id = a.id
JOIN c ON c.id = b.c_id;Exemple commenté
SELECT d.name, m.title
FROM directors d
LEFT JOIN movies m ON m.director_id = d.id;Tous les réalisateurs sont listés. Sara Diaz, qui n'a aucun film, apparaît avec un titre vide (NULL).
| id | name | country |
|---|---|---|
| 1 | Nora Ellis | UK |
| 2 | Paulo Reis | Brazil |
| 3 | Kenji Mori | Japan |
| 4 | Anna Berg | Sweden |
| 5 | Luc Martin | France |
| 6 | Sara Diaz | Spain |
| id | title | genre | year | duration | rating | director_id |
|---|---|---|---|---|---|---|
| 1 | Night Train | Thriller | 2015 | 118 | 7.8 | 1 |
| 2 | Blue Harbor | Drama | 2018 | 102 | 7.1 | 2 |
| 3 | Paper Moon City | Comedy | 2012 | 95 | 6.4 | 5 |
| 4 | Silent Peak | Drama | 2020 | 131 | 8.2 | 3 |
| 5 | Last Signal | Sci-Fi | 2019 | 142 | 7.5 | 1 |
| 6 | Summer Keys | Comedy | 2016 | 88 | 5.9 | 4 |
| 7 | Iron Garden | Sci-Fi | 2021 | 125 | 8 | 3 |
| 8 | Dust and Gold | Western | 2014 | 110 | 6.8 | 2 |
| 9 | The Quiet Hour | Drama | 2022 | 97 | 7.4 | 5 |
| 10 | Deep Current | Thriller | 2017 | 105 | 6.9 | NULL |
Résultat de l’exemple
| name | title |
|---|---|
| Nora Ellis | Last Signal |
| Nora Ellis | Night Train |
| Paulo Reis | Blue Harbor |
| Paulo Reis | Dust and Gold |
| Kenji Mori | Iron Garden |
| Kenji Mori | Silent Peak |
| Anna Berg | Summer Keys |
| Luc Martin | Paper Moon City |
| Luc Martin | The Quiet Hour |
| Sara Diaz | NULL |
À retenir
- LEFT JOIN garde toute la table de gauche.
- LEFT JOIN + IS NULL trouve les « orphelins ».
- Une auto-jointure utilise deux alias pour la même table.
Pièges fréquents
- Un WHERE sur une colonne de la table de droite peut annuler l'effet du LEFT JOIN.
- COUNT(*) compte 1 même quand il n'y a aucune correspondance : utilise COUNT(colonne_de_droite).
Pour aller plus loin
RIGHT JOIN garde toute la table de droite et FULL JOIN garde les deux côtés (disponibles dans SQLite depuis la version 3.39). CROSS JOIN associe chaque ligne à toutes les lignes de l'autre table : c'est le produit cartésien, utile pour générer toutes les combinaisons.
Les 5 exercices du niveau
- Affiche le nom de chaque artiste et son nombre de chansons, y compris les artistes qui n'en ont aucune (0).
- Affiche le nom des membres qui n'ont jamais emprunté de livre.
- Pour chaque prêt, affiche le nom du membre, le titre du livre et la date de prêt.
- Affiche le nom de chaque employé et le nom de son manager (vide pour la personne qui n'en a pas).
- Pour chaque client, affiche son nom et le nombre de ses commandes non expédiées, c'est-à-dire dont le statut est différent de 'shipped' (not_shipped). Les clients qui n'en ont aucune doivent apparaître avec 0.
Dans SpeedQL, chaque requête est corrigée tout de suite : le résultat est comparé à celui attendu, puis la requête est relancée sur une base de contrôle cachée. Chaque exercice a ses indices écrits, à afficher seulement si tu bloques.
Voir aussi : la fiche de l’aide-mémoire · les exercices SQL corrigés sur cette notion
Faire les exercices du niveau 10
Gratuit, sans inscription : la leçon et les 5 exercices s’ouvrent directement dans ton navigateur.
← Niveau précédent : Relier deux tables avec JOIN · Niveau suivant : Conditions dans le résultat : CASE →