SQL LEFT JOIN : renvoyer des lignes avec correspondances facultatives

SQL LEFT JOIN renvoie chaque ligne de la table de gauche et y rattache les lignes correspondantes de la table de droite. En SQL, c’est une jointure externe : lorsqu’aucune correspondance n’existe, les colonnes de droite sont remplies avec NULL. Utilisez-la quand vous devez conserver tous les enregistrements d’une table, même sans données liées, par exemple pour lister tous les clients qu’ils aient passé commande ou non. LEFT JOIN et LEFT OUTER JOIN sont des mots-clés identiques ; OUTER est facultatif.

Exemple SQL LEFT JOIN pour renvoyer toutes les lignes

Sortie :

La sortie apparaîtra ici...

Sortie :

+------+-------+
| nom  | total |
+------+-------+
| Alma | 79    |
| Alma | 150   |
| Ben  | NULL  |
| Cara | 45    |
+------+-------+
4 row(s)

Comment cet exemple fonctionne

  1. clients contient trois personnes ; commandes contient trois commandes liées par client_id.
  2. LEFT JOIN commandes o ON o.client_id = c.id associe chaque client à chaque commande qui correspond à son id. Alma a deux commandes, donc elle produit deux lignes en sortie.
  3. Ben n’a aucune commande. LEFT JOIN conserve sa ligne et remplit o.total avec NULL au lieu de l’exclure du résultat (ce que ferait INNER JOIN).
  4. ORDER BY c.id, o.id garde la sortie groupée par client et stable à l’intérieur de chaque client. Le NULL dans la colonne total de Ben signale l’absence de correspondance, pas une commande à valeur zéro.

ON vs WHERE : pourquoi l’emplacement du filtre compte

Placer un filtre sur la table de droite dans WHERE au lieu de ON est l’erreur la plus fréquente avec LEFT JOIN : cela transforme silencieusement la jointure externe en jointure interne.

-- Faux : WHERE supprime Ben car son o.total est NULL
SELECT c.nom, o.total
FROM clients c
LEFT JOIN commandes o ON o.client_id = c.id
WHERE o.total > 50;

-- Correct : ON filtre pendant la correspondance, Ben reste avec des NULL
SELECT c.nom, o.total
FROM clients c
LEFT JOIN commandes o ON o.client_id = c.id AND o.total > 50;

Les conditions de ON sont évaluées pendant la jointure : les lignes de gauche sans correspondance apparaissent toujours avec des NULL. WHERE s’exécute après la jointure, donc filtre toutes les lignes où la colonne de droite est NULL, ce qui supprime précisément les lignes que LEFT JOIN doit préserver.

Anti-join : trouver les lignes sans correspondance

LEFT JOIN combiné à un test IS NULL sur une colonne de la table de droite est une méthode standard pour trouver des enregistrements liés manquants :

SELECT c.nom
FROM clients c
LEFT JOIN commandes o ON o.client_id = c.id
WHERE o.id IS NULL;

Cela renvoie uniquement Ben, le client qui n’a aucune commande. Ce motif fonctionne parce que o.id est NULL uniquement pour les lignes de gauche sans correspondance. NOT EXISTS donne le même résultat et peut être plus lisible quand aucune colonne de la table de droite n’est nécessaire dans la sortie.

LEFT JOIN vs INNER JOIN

LEFT JOININNER JOIN
Toutes les lignes de gauche, NULL pour les colonnes de droite sans correspondanceUniquement les lignes qui correspondent des deux côtés
Nombre de lignes ≥ nombre de lignes de la table de gaucheNombre de lignes ≤ nombre de lignes de la plus petite table
À utiliser quand les lignes sans correspondance ont du sens (rapports, contrôles de complétude)À utiliser quand chaque ligne du résultat doit avoir des données valides des deux tables

Règle : commencez avec LEFT JOIN quand conserver toutes les lignes de gauche est important. Passez à INNER JOIN quand les lignes sans correspondance sont non pertinentes ou invalides.

Erreurs courantes avec SQL LEFT JOIN

Multiplication des lignes dans les jointures un-à-plusieurs

LEFT JOIN produit une ligne de sortie par paire correspondante. Si un client a dix commandes, ce client apparaît dix fois. Agréger sans tenir compte de cela gonfle les totaux.

-- Faux : compte les lignes de commande, pas les clients
SELECT COUNT(*) FROM clients c
LEFT JOIN commandes o ON o.client_id = c.id;

-- Correct : compter les clients distincts
SELECT COUNT(DISTINCT c.id) FROM clients c
LEFT JOIN commandes o ON o.client_id = c.id;

Utiliser SELECT * avec des jointures

SELECT * dans une requête avec jointure renvoie des noms de colonnes en double (c.id et o.id), ce qui crée de la confusion dans le code applicatif. Listez toujours explicitement les colonnes nécessaires.

Notes de performance

Indexez la clé de jointure sur la table de droite (commandes.client_id) pour que le moteur puisse chercher les correspondances au lieu de balayer la table. Pour une grande table de droite où seule une partie des lignes est pertinente, préfiltrez avec une sous-requête ou déplacez le filtre dans la clause ON, pas dans WHERE, pour réduire le coût de jointure tout en conservant la sémantique de LEFT JOIN.

FAQ

Quelle est la différence entre LEFT JOIN et LEFT OUTER JOIN ?

Aucune. LEFT JOIN et LEFT OUTER JOIN sont des synonymes définis par le standard SQL. Toutes les bases majeures (PostgreSQL, MySQL, SQLite, SQL Server, Oracle) les traitent de manière identique. La plupart des développeurs omettent OUTER pour aller à l’essentiel.

Pourquoi mon LEFT JOIN renvoie-t-il moins de lignes après l’ajout d’une clause WHERE ?

Un filtre WHERE sur une colonne de la table de droite supprime les lignes étendues avec NULL, ce qui transforme le LEFT JOIN en INNER JOIN effectif. Déplacez la condition dans la clause ON pour conserver les lignes de gauche sans correspondance dans le résultat.

Quand utiliser LEFT JOIN au lieu de INNER JOIN ?

Utilisez LEFT JOIN quand les lignes de gauche doivent apparaître dans la sortie avec ou sans correspondance : rapports de complétude, contrôles de données manquantes et enrichissement optionnel. Utilisez INNER JOIN quand seules les lignes correspondantes sont valides et que les lignes sans correspondance doivent être exclues.