Les jointures SQL : INNER JOIN, LEFT JOIN, RIGHT JOIN
Dans une base de données relationnelle, les informations sont volontairement réparties dans plusieurs tables : les clients d'un côté, les commandes de l'autre. Pour répondre à une question qui mobilise les deux, il faut les recoller : c'est le rôle de la jointure. Si vous cherchez les jointures SQL expliquées simplement pour le DCG, vous êtes au bon endroit : INNER JOIN, LEFT JOIN et RIGHT JOIN sont les trois seuls opérateurs de jointure exigés à l'UE 8, et ils tombent presque chaque année.
Pourquoi joindre des tables ?
L'analogie est simple : vous disposez d'une liste de commandes qui mentionne un numéro de client, et d'une liste de clients avec leurs coordonnées. Joindre, c'est rapprocher les deux listes grâce à ce numéro commun. Techniquement, la jointure relie la clé étrangère d'une table (le NumClient stocké dans COMMANDE) à la clé primaire de l'autre (le NumClient qui identifie chaque ligne de CLIENT).
Deux syntaxes produisent le même résultat. La syntaxe classique place la condition de jointure dans le WHERE :
SELECT C.Nom, CO.DateCommande
FROM CLIENT C, COMMANDE CO
WHERE C.NumClient = CO.NumClient ;
La syntaxe normalisée, recommandée, utilise JOIN ... ON :
SELECT C.Nom, CO.DateCommande
FROM CLIENT C
INNER JOIN COMMANDE CO ON C.NumClient = CO.NumClient ;
Les lettres C et CO sont des alias de table : ils raccourcissent l'écriture et lèvent toute ambiguïté quand une colonne porte le même nom dans deux tables.
INNER JOIN : la correspondance des deux côtés
L'INNER JOIN ne conserve que les lignes ayant une correspondance dans les deux tables. Avec CLIENT et COMMANDE : seuls les clients qui ont passé au moins une commande apparaissent dans le résultat. Un client sans commande est purement absent. C'est la jointure par défaut, adaptée à la grande majorité des besoins : « afficher les commandes avec le nom du client », « afficher les produits avec leur catégorie ».
LEFT JOIN : toutes les lignes de gauche, même orphelines
Le LEFT JOIN conserve toutes les lignes de la table de gauche (celle citée en premier), même sans correspondance à droite. Pour les lignes sans correspondance, les colonnes de la table de droite valent NULL. Exemple typique : afficher tous les clients, avec leurs commandes s'ils en ont :
SELECT C.Nom, CO.NumCommande
FROM CLIENT C
LEFT JOIN COMMANDE CO ON C.NumClient = CO.NumClient ;
Un client sans commande apparaît avec NULL dans la colonne NumCommande. Le RIGHT JOIN est simplement le symétrique : il conserve toutes les lignes de la table de droite. En pratique, on peut toujours réécrire un RIGHT JOIN en LEFT JOIN en inversant l'ordre des tables, ce qui explique que le LEFT JOIN soit beaucoup plus utilisé.
Le patron star de l'examen : LEFT JOIN + IS NULL
Comment trouver « ceux qui n'ont rien » : les clients sans commande, les produits jamais vendus ? La méthode : un LEFT JOIN, puis un filtre sur la nullité de la clé de droite.
SELECT C.Nom
FROM CLIENT C
LEFT JOIN COMMANDE CO ON C.NumClient = CO.NumClient
WHERE CO.NumCommande IS NULL ;
Le LEFT JOIN garde tous les clients ; ceux sans commande ont NULL dans les colonnes de COMMANDE ; le WHERE ne retient qu'eux. La formulation équivalente avec sous-requête est WHERE NumClient NOT IN (SELECT NumClient FROM COMMANDE). Les deux méthodes sont acceptées à l'examen et il faut savoir écrire les deux : NOT IN est plus intuitive à lire, LEFT JOIN + IS NULL est plus performante sur de gros volumes et ne souffre pas du piège des NULL dans la sous-requête.
Un exemple chiffré : la société Fournitex
Prenons le cas de la société Fournitex, fournituriste de bureau. Sa table CLIENT contient quatre entreprises : BUREAU PLUS (Lyon), PAPETERIE DU NORD (Lille), OFFICE PRO (Lyon) et ECO BUREAU (Nantes). Sa table COMMANDE contient quatre commandes : deux pour BUREAU PLUS, une pour PAPETERIE DU NORD, une pour OFFICE PRO. ECO BUREAU n'a jamais commandé.
Avec un INNER JOIN entre CLIENT et COMMANDE, le résultat compte quatre lignes : BUREAU PLUS apparaît deux fois (une par commande), PAPETERIE DU NORD et OFFICE PRO une fois chacune. ECO BUREAU est absent. Avec un LEFT JOIN depuis CLIENT, le résultat compte cinq lignes : les quatre précédentes, plus ECO BUREAU avec NULL dans les colonnes de commande. Et le patron LEFT JOIN + IS NULL renvoie exactement une ligne : ECO BUREAU, le client à relancer commercialement. Trois requêtes, trois réponses de gestion différentes : tout l'enjeu est de choisir la bonne jointure pour le bon besoin.
Les erreurs fréquentes
- Oublier la condition de jointure :
SELECT * FROM CLIENT, COMMANDE sans WHERE ni ON produit un produit cartésien (chaque client combiné avec chaque commande), résultat absurde et volumineux.
- Utiliser un INNER JOIN quand le besoin exige un LEFT JOIN : « le nombre de commandes par client, y compris ceux qui n'ont rien commandé » impose le LEFT JOIN, sinon les clients inactifs disparaissent.
- Mal placer une condition de filtre avec un LEFT JOIN : une condition sur la table de droite placée dans le WHERE (plutôt que dans le ON) transforme silencieusement le LEFT JOIN en INNER JOIN.
- Oublier les alias de table quand une colonne existe des deux côtés : NumClient sans préfixe est ambigu et provoque une erreur.
- Enchaîner les jointures dans le désordre : pour relier PRODUIT à COMMANDE via LIGNECOMMANDE, il faut suivre le chemin des clés étrangères, table par table.
- Croire que RIGHT JOIN apporte quelque chose de plus : c'est le miroir du LEFT JOIN ; mieux vaut maîtriser parfaitement ce dernier.
FAQ
Comment choisir entre INNER JOIN et LEFT JOIN ?
Posez la question : faut-il conserver les lignes sans correspondance ? Si le besoin porte uniquement sur les éléments liés (les clients qui ont commandé), INNER JOIN. Si le besoin exige l'exhaustivité d'un côté (tous les clients, avec ou sans commande), LEFT JOIN depuis cette table.
Peut-on joindre plus de deux tables ?
Oui, en enchaînant les JOIN : par exemple CLIENT joint à COMMANDE, elle-même jointe à LIGNECOMMANDE, elle-même jointe à PRODUIT. Chaque jointure suit une relation clé primaire / clé étrangère. C'est le schéma type des questions d'examen sur le montant des commandes.
Quelle différence entre NOT IN et LEFT JOIN + IS NULL ?
Les deux trouvent les lignes sans correspondance et sont acceptées à l'examen. NOT IN est plus lisible, mais si la sous-requête contient des NULL, elle peut renvoyer un résultat vide (piège classique). LEFT JOIN + IS NULL est plus robuste et plus performant sur de gros volumes : c'est la forme privilégiée en entreprise.
Entraînez-vous
Sur la base CLIENT(NumClient, Nom, Ville), COMMANDE(NumCommande, DateCommande, NumClient) et LIGNECOMMANDE(NumCommande, CodeProduit, Quantite), écrivez : 1) la requête affichant le nom de chaque client avec la date de ses commandes ; 2) la requête affichant les clients qui n'ont jamais commandé, par deux méthodes différentes.
Afficher le corrigé
Question 1 : une jointure interne suffit, car on ne veut que les clients ayant des commandes.
SELECT C.Nom, CO.DateCommande
FROM CLIENT C
INNER JOIN COMMANDE CO ON C.NumClient = CO.NumClient ;
La condition ON relie la clé étrangère NumClient de COMMANDE à la clé primaire NumClient de CLIENT. Un client ayant passé trois commandes apparaîtra trois fois : c'est normal, chaque ligne du résultat représente une commande.
Question 2, méthode 1 : sous-requête avec NOT IN.
SELECT Nom
FROM CLIENT
WHERE NumClient NOT IN (SELECT NumClient FROM COMMANDE) ;
La sous-requête liste les numéros de clients présents dans COMMANDE ; NOT IN exclut ces clients, ne laissant que ceux qui n'ont jamais commandé.
Question 2, méthode 2 : LEFT JOIN + IS NULL.
SELECT C.Nom
FROM CLIENT C
LEFT JOIN COMMANDE CO ON C.NumClient = CO.NumClient
WHERE CO.NumCommande IS NULL ;
Le LEFT JOIN conserve tous les clients ; ceux sans commande ont NULL dans CO.NumCommande ; le filtre IS NULL les isole. Les deux méthodes produisent le même résultat : il faut savoir écrire les deux, l'examinateur pouvant imposer l'une ou l'autre.