SQL Quest
Se connecter English 0 XP Niv. 1
Intermédiaire

SQL LEFT JOIN : garder les lignes sans correspondance

5 min de lecture · 4 exemples exécutables · mis à jour le 9 octobre 2026

Avec un INNER JOIN, un client qui n'a jamais commandé disparaît du résultat. Or c'est parfois justement lui qu'on cherche : les clients inactifs, les produits jamais vendus, les fournisseurs sans produit… LEFT JOIN résout ce problème : il garde toutes les lignes de la table de gauche, qu'elles aient une correspondance ou non.

Syntaxe

SELECT a.colonne, b.colonne
FROM table_a a
LEFT JOIN table_b b ON b.cle = a.cle;

Comment ça marche

Gauche et droite

La table « de gauche » est celle écrite après FROM ; celle « de droite » est celle du LEFT JOIN. Toutes les lignes de gauche sont gardées. Quand une ligne de gauche n'a aucune correspondance à droite, les colonnes de droite valent NULL.

LEFT JOIN ou INNER JOIN ?

INNER JOINLEFT JOIN
Ligne de gauche avec correspondancegardéegardée
Ligne de gauche sans correspondancesuppriméegardée, avec des NULL à droite

Trouver ce qui manque

Le motif le plus utile du LEFT JOIN : LEFT JOIN … WHERE droite.id IS NULL. Il ne garde que les lignes de gauche sans aucune correspondance : les clients sans commande, les produits jamais vendus, etc.

RIGHT JOIN et FULL JOIN

RIGHT JOIN fait la même chose en gardant la table de droite ; on peut toujours l'écrire comme un LEFT JOIN en inversant les tables. FULL OUTER JOIN garde les lignes des deux côtés. SQLite les accepte depuis sa version 3.39.

Schéma

clients
idprenom
1Léa
2Hugo
3Inès
commandes
idclient_id
101
111
122
résultat
prenomcommande
Léa10
Léa11
Hugo12
InèsNULL
clients LEFT JOIN commandes : Inès n'a pas de commande, elle est gardée avec NULL dans les colonnes de commandes.

Schéma simplifié pour illustrer le principe. Les exemples ci-dessous utilisent la vraie base d'exercices de SQL Quest (une boutique en ligne fictive : voir le schéma complet).

Exemples avec leurs résultats

1. Garder tous les clients

Chaque client avec son nombre de commandes, y compris ceux qui n'en ont aucune (0).

SELECT c.id, c.prenom, c.nom, COUNT(o.id) AS nb_commandes
FROM clients c
LEFT JOIN commandes o ON o.client_id = c.id
GROUP BY c.id
ORDER BY nb_commandes
LIMIT 8;
Essayer dans le bac à sable
Résultat
idprenomnomnb_commandes
111ManonRoux0
112AliceBernard0
113EmmaMoreau0
114NathanLefebvre0
115SarahSimon0
116KarimLefebvre0
117ThéoChevalier0
118ChloéLambert0

8 lignes au total

2. Trouver les lignes sans correspondance

Les clients qui n'ont jamais passé de commande.

SELECT c.id, c.prenom, c.nom, c.ville
FROM clients c
LEFT JOIN commandes o ON o.client_id = c.id
WHERE o.id IS NULL;
Essayer dans le bac à sable
Résultat
idprenomnomville
111ManonRouxStrasbourg
112AliceBernardNantes
113EmmaMoreauBordeaux
114NathanLefebvreMarseille
115SarahSimonLyon
116KarimLefebvreNantes
117ThéoChevalierMontréal
118ChloéLambertNantes
119LucasBenaliBordeaux
120InèsLambertParis

10 lignes au total

3. Comparer avec INNER JOIN

Le nombre de clients obtenu avec chaque type de jointure : la différence correspond aux clients sans commande.

SELECT
  (SELECT COUNT(DISTINCT c.id) FROM clients c JOIN commandes o ON o.client_id = c.id) AS avec_inner_join,
  (SELECT COUNT(DISTINCT c.id) FROM clients c LEFT JOIN commandes o ON o.client_id = c.id) AS avec_left_join;
Essayer dans le bac à sable
Résultat
avec_inner_joinavec_left_join
110120

1 ligne au total

4. Les employés qui n'ont géré aucune commande

La direction ne traite pas de commandes : ces employés n'ont aucune correspondance.

SELECT e.prenom, e.nom, e.poste
FROM employes e
LEFT JOIN commandes o ON o.employe_id = e.id
WHERE o.id IS NULL;
Essayer dans le bac à sable
Résultat
prenomnomposte
ChloéDuboisPDG
JadeLefebvreDirecteur commercial
NathanRouxDirectrice technique
SamirSimonResponsable RH

4 lignes au total

Les erreurs fréquentes

Filtrer la table de droite dans le WHERE

Une condition sur la table de droite dans le WHERE élimine les lignes où elle vaut NULL : le LEFT JOIN se comporte alors comme un INNER JOIN. Placez cette condition dans le ON.

À éviter
SELECT c.prenom, o.id FROM clients c LEFT JOIN commandes o ON o.client_id = c.id WHERE o.statut = 'annulée';
Correct
SELECT c.prenom, o.id FROM clients c LEFT JOIN commandes o ON o.client_id = c.id AND o.statut = 'annulée';

Compter avec COUNT(*)

Pour un client sans commande, la ligne existe quand même (avec des NULL) : COUNT(*) donne 1 au lieu de 0. Comptez une colonne de droite.

À éviter
SELECT c.id, COUNT(*) FROM clients c LEFT JOIN commandes o ON o.client_id = c.id GROUP BY c.id;
Correct
SELECT c.id, COUNT(o.id) FROM clients c LEFT JOIN commandes o ON o.client_id = c.id GROUP BY c.id;

Inverser les tables

La table dont on veut garder toutes les lignes doit être à gauche, juste après FROM.

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

Exercices

Essayez d'écrire la requête vous-même avant d'ouvrir la solution.

Défi 1. Affichez tous les fournisseurs avec leur nombre de produits, y compris ceux qui n'en ont aucun.

Voir une solution
SELECT f.nom, COUNT(p.id) AS nb_produits FROM fournisseurs f LEFT JOIN produits p ON p.fournisseur_id = f.id GROUP BY f.id;
nomnb_produits
TechNova1
ElectroPlus2
MaisonDeco4
SportZone13
BookWorld1
GreenFood5
AsiaParts3

7 lignes au total

Essayer dans le bac à sable

Défi 2. Affichez tous les employés avec le nombre de commandes qu'ils ont gérées, y compris ceux qui n'en ont géré aucune (0), du plus petit nombre au plus grand.

Voir une solution
SELECT e.prenom, e.nom, COUNT(o.id) AS nb_commandes FROM employes e LEFT JOIN commandes o ON o.employe_id = e.id GROUP BY e.id ORDER BY nb_commandes LIMIT 8;
prenomnomnb_commandes
ChloéDubois0
JadeLefebvre0
NathanRoux0
SamirSimon0
LouisGarcia18
LouisLambert20
InèsMoreau21
ChloéBenali22

8 lignes au total

Essayer dans le bac à sable
Envie de vous entraîner davantage ?

Les exercices interactifs sont corrigés automatiquement, avec un prof qui explique vos erreurs. Une leçon résumée reste affichée à côté de l'éditeur.

Faire les exercices interactifs

Questions fréquentes

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

INNER JOIN ne garde que les lignes qui ont une correspondance dans les deux tables. LEFT JOIN garde toutes les lignes de la table de gauche, et met NULL dans les colonnes de droite quand il n'y a pas de correspondance.

LEFT JOIN et LEFT OUTER JOIN, c'est pareil ?

Oui, le mot OUTER est facultatif.

Pourquoi mon LEFT JOIN renvoie-t-il plus de lignes que la table de gauche ?

Parce qu'une ligne de gauche est répétée autant de fois qu'elle a de correspondances à droite. Un client avec 5 commandes apparaît 5 fois.

Comment trouver les clients sans commande ?

Avec LEFT JOIN commandes … WHERE commandes.id IS NULL, ou avec WHERE NOT EXISTS (SELECT 1 FROM commandes WHERE client_id = clients.id).

À lire ensuite