Le LEFT JOIN est une instruction SQL qui garantit la conservation de chaque enregistrement de la table principale, celle déclarée dans la clause FROM. Lorsqu’une ligne de cette table ne trouve aucun équivalent dans la table associée, les colonnes issues de cette dernière reçoivent automatiquement la valeur NULL. Les paires identifiées par le critère de liaison sont intégrées au résultat avec leurs valeurs respectives des deux côtés. Le mot-clé OUTER est facultatif : les deux formulations sont fonctionnellement interchangeables selon la norme SQL ISO/IEC. C’est systématiquement la table déclarée en premier qui est prioritaire, et dont aucun enregistrement ne sera écarté du résultat final.
Table des matières
Syntaxe générique de LEFT JOIN
La syntaxe du LEFT JOIN requiert une clause ON obligatoire pour définir le critère d’appariement entre les deux tables engagées dans la liaison. Sans cette condition, le moteur SQL ne peut pas déterminer quelles lignes doivent être mises en correspondance entre les deux ensembles de données. Une alternative avec USING est disponible lorsque la colonne de liaison porte exactement le même nom dans les deux tables. MySQL, PostgreSQL, SQL Server et SQLite supportent tous cette opération nativement, avec un comportement conforme à la norme SQL. La clause ON accepte plusieurs critères combinés avec AND pour affiner les conditions d’appariement selon la complexité du modèle de données.
La syntaxe standard d’une jointure gauche entre deux tables s’écrit ainsi :
SELECT table1.colonne1, table2.colonne2
FROM table1
LEFT JOIN table2 ON table1.id = table2.id;
L’intégralité des lignes de table1 figure dans le résultat, complétée par les valeurs de table2 lorsqu’un équivalent existe. Les colonnes de table2 affichent NULL pour chaque enregistrement de table1 sans équivalent dans la table associée.
Lorsque la colonne de liaison porte le même identifiant dans les deux tables, la syntaxe avec USING allège considérablement l’écriture :
SELECT table1.colonne1, table2.colonne2
FROM table1
LEFT JOIN table2 USING (id);
Cette formulation produit un résultat strictement identique à la précédente sur les mêmes données. Vérifiez que la colonne mentionnée dans USING existe avec le même nom et le même type dans les deux tables avant d’adopter cette syntaxe allégée.
Comment fonctionne un LEFT JOIN en SQL ?
Le moteur SQL parcourt d’abord l’intégralité des enregistrements de la table principale, celle déclarée dans FROM. Pour chaque ligne de cette table prioritaire, il cherche un équivalent dans la table associée selon le critère défini dans ON. Lorsqu’une paire est identifiée, les valeurs des deux tables sont assemblées en une seule ligne dans le jeu de résultats retourné. Lorsqu’aucun équivalent n’existe, la ligne de la table prioritaire est tout de même conservée avec des valeurs NULL pour toutes les colonnes issues de la table associée. Les lignes de la table associée sans équivalent dans la table prioritaire sont en revanche entièrement écartées du résultat.
L’exemple suivant illustre ce mécanisme avec une table clients et une table commandes, dont certains comptes n’ont jamais généré d’activité transactionnelle :
SELECT clients.nom, commandes.id_commande
FROM clients
LEFT JOIN commandes ON clients.id_client = commandes.id_client;
L’intégralité des comptes clients figure dans le résultat, y compris ceux sans aucun achat enregistré. Les colonnes issues de commandes affichent NULL pour les comptes sans historique, ce qui permet d’identifier immédiatement les profils inactifs dans la base.
Pourquoi un LEFT JOIN retourne-t-il des valeurs NULL ?
Les valeurs NULL présentes dans le résultat d’une jointure gauche signalent que la ligne concernée de la table prioritaire n’a trouvé aucun équivalent dans la table associée. Ces valeurs ne proviennent pas des données sources : elles sont générées par le moteur SQL pour combler les colonnes manquantes dans les lignes orphelines. Il est essentiel de distinguer un NULL produit par l’absence de correspondance d’un NULL déjà stocké dans les données d’origine, car les deux traduisent des situations métier différentes. Pour identifier l’origine d’une valeur absente, contrôlez directement dans la table source si ce champ était déjà vide avant l’exécution de la requête. Cette vérification est indispensable lors d’un contrôle de cohérence ou d’un audit d’intégrité entre deux ensembles de données liés.
Quand utiliser un LEFT JOIN en SQL ?
La jointure gauche est l’opération de liaison la plus répandue en SQL car elle couvre la grande majorité des besoins analytiques et de reporting courants. Il est adapté dès qu’un référentiel doit apparaître intégralement dans le résultat, même lorsque certaines de ses entrées ne trouvent pas d’équivalent dans la table associée. Ce besoin se manifeste pour produire un catalogue complet de produits avec leurs ventes, un registre exhaustif de clients avec leurs commandes, ou un annuaire d’employés avec leurs affectations. Il est également incontournable pour détecter des anomalies d’intégrité, en ciblant les enregistrements dont les colonnes de la table associée restent vides après la liaison. La documentation officielle PostgreSQL décrit explicitement cette opération comme la jointure externe la plus naturelle pour exprimer une relation optionnelle entre deux tables d’un schéma relationnel.
L’exemple suivant produit un catalogue exhaustif de produits avec leurs transactions de vente, y compris les références sans aucune activité commerciale enregistrée :
SELECT produits.nom_produit, ventes.montant
FROM produits
LEFT JOIN ventes ON produits.id_produit = ventes.id_produit;
Toutes les références du catalogue figurent dans le résultat, même celles dont la colonne montant reste vide. Ce jeu de données permet d’identifier sans ambiguïté les articles pour lesquels aucune transaction n’a encore été enregistrée dans la base.
Comment effectuer un LEFT JOIN sur plusieurs tables ?
Une jointure gauche peut être enchaînée sur autant de tables que nécessaire, chaque liaison étant ajoutée séquentiellement à la suite de la précédente. Chaque étape de la chaîne doit être accompagnée de sa propre clause ON qui définit le critère de liaison avec la table précédemment engagée. Il est fortement déconseillé d’intercaler un INNER JOIN sur une table déjà couverte par une jointure gauche, car cela annule silencieusement la conservation des enregistrements orphelins. Lorsque la deuxième table contient des lignes sans équivalent, la colonne de liaison vers la troisième table reçoit NULL, ce qui empêche tout appariement dans les niveaux suivants de la chaîne. Il convient donc d’utiliser systématiquement une jointure gauche pour toutes les tables qui suivent la première liaison gauche, afin de préserver l’exhaustivité du résultat tout au long de la chaîne.
L’exemple suivant enchaîne trois tables pour produire une liste complète de clients avec leurs commandes et les produits associés, sans exclure les comptes sans achat :
SELECT clients.nom, commandes.id_commande, produits.nom_produit
FROM clients
LEFT JOIN commandes ON clients.id_client = commandes.id_client
LEFT JOIN produits ON commandes.id_produit = produits.id_produit;
Les clients sans commande apparaissent avec NULL dans les colonnes id_commande et nom_produit, conformément au comportement attendu d’une chaîne de jointures gauches. Vérifiez que chaque liaison supplémentaire utilise une colonne de liaison issue d’une table déjà présente dans la requête et non d’une table encore à engager.
Pourquoi un LEFT JOIN avec WHERE se comporte-t-il comme un INNER JOIN ?
Ce comportement est l’une des erreurs de conception les plus fréquentes en SQL : placer un filtre WHERE sur une colonne de la table associée transforme silencieusement la jointure gauche en liaison interne. Lorsque la clause WHERE impose une condition sur une colonne de la table droite sans autoriser la valeur NULL, les enregistrements orphelins sont automatiquement écartés du résultat. Or ces lignes orphelines ont précisément NULL dans les colonnes de la table associée, ce qui les fait systématiquement échouer au filtre. La raison est que le moteur SQL applique d’abord la liaison, puis le filtre WHERE : les enregistrements sans équivalent sont inclus dans la jointure mais éliminés lors de l’évaluation du filtre. Pour conserver l’exhaustivité d’une liaison gauche tout en filtrant sur la table associée, la condition doit être déplacée dans la clause ON et non dans WHERE.
L’exemple suivant illustre la différence de comportement entre les deux formulations sur le même besoin métier :
-- Jointure gauche annulée par le filtre WHERE
SELECT clients.nom, commandes.statut
FROM clients
LEFT JOIN commandes ON clients.id_client = commandes.id_client
WHERE commandes.statut = 'livré';
-- Jointure gauche préservée avec le filtre dans ON
SELECT clients.nom, commandes.statut
FROM clients
LEFT JOIN commandes ON clients.id_client = commandes.id_client
AND commandes.statut = 'livré';
La première requête écarte tous les clients sans commande au statut « livré », ce qui neutralise l’effet de la jointure gauche. La seconde conserve l’intégralité des clients : ceux sans équivalent dans commandes affichent NULL dans la colonne statut, conformément au comportement attendu.
Comment détecter des enregistrements orphelins avec un LEFT JOIN ?
Un enregistrement orphelin est une ligne de la table prioritaire qui ne trouve aucun équivalent dans la table associée selon le critère d’appariement défini. Pour les isoler, une clause WHERE ... IS NULL cible les lignes dont une colonne issue de la table associée reste vide après la liaison. Cette technique est régulièrement utilisée pour contrôler la cohérence entre deux tables liées par une clé étrangère dans un schéma relationnel. Elle permet de repérer des produits sans catégorie assignée, des commandes sans client référencé, ou des utilisateurs sans rôle attribué dans un système de gestion des accès. La colonne utilisée dans le filtre WHERE ... IS NULL doit impérativement provenir de la table associée et non de la table prioritaire pour que le ciblage fonctionne correctement.
L’exemple suivant extrait tous les clients pour lesquels aucune commande n’a jamais été enregistrée dans la base de données :
SELECT clients.id_client, clients.nom
FROM clients
LEFT JOIN commandes ON clients.id_client = commandes.id_client
WHERE commandes.id_client IS NULL;
Seuls les profils absents de la table commandes apparaissent dans ce résultat, ce qui cible précisément les comptes sans activité à analyser ou les anomalies d’intégrité à corriger. Vérifiez que la colonne filtrée dans WHERE provient bien de la table associée commandes et non de la table prioritaire clients pour obtenir le comportement attendu.
Sources: MySql, Postgres