OUTER JOIN en SQL est l’opérateur SQL qui assemble les enregistrements de deux tables tout en conservant les lignes sans correspondance, en affichant NULL pour les colonnes manquantes. Contrairement à INNER JOIN, une jointure externe ne se limite pas aux seuls enregistrements appariés entre les deux tables interrogées.
Table des matières
Syntaxe de OUTER JOIN en SQL
La syntaxe de OUTER JOIN suit la structure de base suivante avec l’ajout du qualificatif LEFT, RIGHT ou FULL pour préciser quelle table conserve ses enregistrements sans correspondance. La clause ON reste obligatoire et définit la condition d’égalité entre les colonnes de liaison des deux tables. Le mot-clé OUTER est facultatif mais recommandé pour expliciter l’intention dans un environnement collaboratif.
La structure de base respecte toujours cet ordre :
SELECT colonnes
FROM table_gauche
[LEFT | RIGHT | FULL] OUTER JOIN table_droite ON table_gauche.colonne = table_droite.colonne;
Comment fonctionne une jointure externe ?
Une jointure externe étend le résultat d’une liaison classique en incluant les enregistrements qui n’ont pas d’équivalent dans la table opposée. Les colonnes issues de la table sans correspondance reçoivent automatiquement la valeur NULL pour signaler l’absence de données. Ce mécanisme est important pour analyser des données incomplètes ou détecter des enregistrements orphelins dans un schéma relationnel.
SQL propose trois variantes de jointure externe, chacune définissant quel côté de la liaison conserve ses enregistrements sans équivalent :
| Opérateur | Comportement |
|---|---|
LEFT OUTER JOIN | Toutes les lignes de la table gauche, NULL si aucun équivalent à droite |
RIGHT OUTER JOIN | Toutes les lignes de la table droite, NULL si aucun équivalent à gauche |
FULL OUTER JOIN | Toutes les lignes des deux tables, NULL de part et d’autre si absence de correspondance |
Le mot-clé OUTER est facultatif dans les trois cas : LEFT JOIN, RIGHT JOIN et FULL JOIN produisent un résultat strictement identique. La formulation complète avec OUTER est néanmoins recommandée pour expliciter l’intention du développeur dans un environnement collaboratif.
Les deux tables de référence utilisées dans l’ensemble des exemples suivants :
-- Clients enregistrés dans la base
CREATE TABLE clients (
id INT PRIMARY KEY,
nom VARCHAR(100),
ville VARCHAR(100)
);
-- Achats liés à chaque client
CREATE TABLE commandes (
id INT PRIMARY KEY,
client_id INT, -- clé étrangère vers clients.id
produit VARCHAR(100),
montant DECIMAL(10,2)
);
Qu’est-ce qu’une jointure externe gauche ?
Une jointure externe gauche retourne la totalité des enregistrements de la table positionnée à gauche de l’opérateur, qu’une correspondance existe ou non dans la table de droite. C’est la variante la plus utilisée en production parmi les jointures externes. Elle couvre des cas comme recenser tous les clients, y compris ceux sans aucun achat enregistré.
On y recourt lorsqu’il est impératif de ne perdre aucun enregistrement de la table principale, même en l’absence de données associées dans la table secondaire.
-- Recenser tous les clients, avec leurs achats si disponibles
SELECT c.nom AS acheteur, cmd.produit, cmd.montant
FROM clients AS c
LEFT OUTER JOIN commandes AS cmd ON c.id = cmd.client_id;
Cette requête retourne tous les profils enregistrés dans la table clients, qu’ils aient passé une commande ou non. Pour les acheteurs sans historique, les colonnes produit et montant affichent NULL. Pour isoler uniquement les clients sans activité, on ajoute WHERE cmd.id IS NULL après la jointure.
À quoi sert une jointure externe droite ?
Une jointure externe droite permet d’inverser la logique de LEFT OUTER JOIN : c’est la table de droite qui conserve la totalité de ses enregistrements. Les attributs de la table gauche prennent la valeur NULL en l’absence d’équivalent. Cet opérateur est peu utilisé en pratique car inverser l’ordre des tables dans un LEFT OUTER JOIN produit un résultat identique avec une meilleure lisibilité.
On l’utilise lorsque la table secondaire doit impérativement conserver tous ses enregistrements dans le résultat final, indépendamment des correspondances trouvées côté table principale.
-- Lister toutes les transactions, avec le profil acheteur si disponible
SELECT c.nom AS acheteur, cmd.produit, cmd.montant
FROM clients AS c
RIGHT OUTER JOIN commandes AS cmd ON c.id = cmd.client_id;
Cette instruction retourne toutes les lignes de commandes, même celles dont le client_id ne correspond à aucun enregistrement dans la table clients. Les colonnes nom et ville affichent NULL pour les transactions orphelines. Ces occurrences signalent généralement une incohérence référentielle à corriger dans la base.
Qu’est-ce qu’une jointure externe entière ?
Une jointure externe entière est une jointure qui restitue l’intégralité des enregistrements des deux tables, en plaçant NULL là où aucune liaison ne peut être établie. C’est l’union complète des résultats d’un LEFT OUTER JOIN et d’un RIGHT OUTER JOIN appliqués simultanément. Son usage est réservé aux audits de données ou aux rapprochements d’ensembles hétérogènes.
PostgreSQL et SQL Server supportent cet opérateur nativement. MySQL ne le prend pas en charge directement et nécessite une simulation via UNION.
-- PostgreSQL / SQL Server : union complète des deux tables
SELECT c.nom AS acheteur, cmd.produit, cmd.montant
FROM clients AS c
FULL OUTER JOIN commandes AS cmd ON c.id = cmd.client_id;
-- MySQL : simulation avec UNION
SELECT c.nom AS acheteur, cmd.produit, cmd.montant
FROM clients AS c
LEFT OUTER JOIN commandes AS cmd ON c.id = cmd.client_id
UNION
SELECT c.nom AS acheteur, cmd.produit, cmd.montant
FROM clients AS c
RIGHT OUTER JOIN commandes AS cmd ON c.id = cmd.client_id;
La première instruction retourne simultanément les clients sans commande et les transactions sans acheteur identifiable. La simulation MySQL via UNION produit le même périmètre en fusionnant les deux jeux de données et en éliminant les doublons automatiquement. Il faut vérifier que les colonnes sélectionnées dans les deux branches du UNION sont identiques en nombre et en type.
Quelle est la différence entre une jointure interne et une jointure externe ?
Les jointures internes et jointures externes partagent le même mécanisme de liaison via une colonne commune, mais divergent sur un point fondamental : le sort réservé aux enregistrements sans équivalent dans la table opposée. INNER JOIN les élimine, OUTER JOIN les préserve. Ce choix détermine directement le volume et la complétude du jeu de données retourné.
| Critère | INNER JOIN | OUTER JOIN |
|---|---|---|
| Lignes sans correspondance | Exclues | Conservées avec NULL |
| Volume du résultat | Limité aux enregistrements appariés | Peut dépasser la table dominante |
| Cas d’usage principal | Données complètes et cohérentes | Données partielles ou audits |
| Support MySQL | ✅ | ✅ LEFT/RIGHT, ❌ FULL natif |
| Performances | Généralement plus rapide | Plus coûteux sur grands volumes |
Quand utiliser une jointure externe plutôt qu’une jointure interne ?
Une jointure externe s’impose dès que des enregistrements de la table principale peuvent légitimement ne pas avoir d’équivalent dans la table associée. Ce scénario est fréquent dans les bases e-commerce, RH ou analytiques où certaines entités existent indépendamment de toute relation établie. Choisir INNER JOIN dans ce contexte provoque des omissions silencieuses : des lignes valides disparaissent du résultat sans aucun message d’erreur.
Trois situations métier justifient systématiquement le recours à une liaison externe :
- Données incomplètes par nature — un client sans commande, un employé sans projet assigné, un produit sans stock associé
- Détection d’enregistrements orphelins — identifier les lignes sans correspondance dans une table secondaire pour auditer la cohérence référentielle
- Rapprochement de référentiels hétérogènes — comparer deux ensembles de données dont les périmètres ne se recoupent pas entièrement, typiquement avec
FULL OUTER JOIN
À l’inverse, utiliser OUTER JOIN lorsque chaque enregistrement possède obligatoirement un équivalent alourdit inutilement le plan d’exécution et introduit des valeurs NULL non attendues dans le résultat. La décision doit toujours s’appuyer sur une analyse des données réelles et non sur une habitude de rédaction des requêtes.
Comment éviter les jointures externes ?
Une jointure externe est parfois le signe d’un schéma relationnel insuffisamment normalisé ou d’une contrainte d’intégrité référentielle manquante. Avant de recourir à OUTER JOIN, il est utile d’examiner si la structure des tables peut être renforcée pour garantir que chaque enregistrement possède toujours un équivalent dans la table associée. Cette démarche réduit la complexité des requêtes et améliore les performances globales de la base.
Renforcer les contraintes référentielles — déclarer une contrainte FOREIGN KEY avec ON DELETE RESTRICT empêche la création d’enregistrements orphelins à la source. Si chaque commande est obligatoirement rattachée à un acheteur existant, INNER JOIN suffit pour toutes les opérations d’extraction. Cette approche traite le problème structurellement plutôt qu’à l’étape de la requête.
-- Contrainte référentielle pour garantir qu'une commande a toujours un client
ALTER TABLE commandes
ADD CONSTRAINT fk_client
FOREIGN KEY (client_id) REFERENCES clients(id)
ON DELETE RESTRICT;
Utiliser des valeurs par défaut — attribuer une valeur neutre plutôt que NULL aux colonnes facultatives évite les résultats vides qui nécessitent une jointure externe. Une colonne ville avec DEFAULT '' est plus simple à traiter qu’une valeur NULL dans une instruction de liaison. Cette technique convient aux champs non critiques dont l’absence ne traduit pas une incohérence métier.
Restructurer avec une sous-requête — dans certains cas, une sous-requête corrélée remplace avantageusement une jointure externe complexe et améliore la lisibilité du code.
-- Identifier les clients sans achat via sous-requête plutôt que LEFT JOIN
SELECT c.nom, c.ville
FROM clients AS c
WHERE NOT EXISTS (
SELECT 1 FROM commandes AS cmd WHERE cmd.client_id = c.id
);
Cette instruction identifie les profils sans activité sans recourir à une liaison externe. NOT EXISTS est souvent plus performant que LEFT JOIN ... WHERE IS NULL sur les moteurs modernes car il s’arrête dès la première correspondance détectée. Il faut comparer les plans d’exécution des deux approches pour retenir la plus efficace selon le volume de données.
Quelles sont les erreurs courantes lors de l’utilisation d’une jointure externe ?
Plusieurs erreurs récurrentes affectent les requêtes avec OUTER JOIN, souvent difficiles à détecter sans vérification explicite du jeu de données retourné. Certaines produisent des résultats incorrects sans générer de message d’erreur, ce qui les rend particulièrement risquées en environnement de production.
Filtrer sur la table externe dans WHERE plutôt que dans ON — placer une condition sur la table de droite dans WHERE transforme silencieusement un LEFT OUTER JOIN en liaison interne, en éliminant les lignes dont les colonnes sont NULL.
-- ❌ Incorrect : le filtre WHERE annule l'effet du LEFT JOIN sur les lignes NULL
SELECT c.nom, cmd.montant
FROM clients AS c
LEFT OUTER JOIN commandes AS cmd ON c.id = cmd.client_id
WHERE cmd.montant > 100;
-- ✅ Correct : le filtre est intégré dans la clause ON pour préserver les profils sans achat
SELECT c.nom, cmd.montant
FROM clients AS c
LEFT OUTER JOIN commandes AS cmd ON c.id = cmd.client_id AND cmd.montant > 100;
Dans la version incorrecte, les clients sans commande disparaissent du résultat car NULL > 100 est évalué à FALSE par le moteur. Déplacer la condition dans ON préserve ces profils tout en filtrant les transactions concernées. Il faut systématiquement vérifier l’emplacement des conditions de filtrage lors de l’utilisation d’une liaison externe.
Utiliser FULL OUTER JOIN sur MySQL sans simulation — MySQL ne supporte pas FULL OUTER JOIN nativement et retourne une erreur de syntaxe à l’exécution. Il faut obligatoirement simuler cet opérateur via UNION entre un LEFT et un RIGHT OUTER JOIN.
-- ❌ Incorrect sur MySQL : syntaxe non supportée
SELECT c.nom, cmd.produit
FROM clients AS c
FULL OUTER JOIN commandes AS cmd ON c.id = cmd.client_id;
-- ✅ Correct sur MySQL : simulation via UNION
SELECT c.nom, cmd.produit
FROM clients AS c
LEFT OUTER JOIN commandes AS cmd ON c.id = cmd.client_id
UNION
SELECT c.nom, cmd.produit
FROM clients AS c
RIGHT OUTER JOIN commandes AS cmd ON c.id = cmd.client_id;
Omettre la clause ON — l’absence de condition de liaison génère un produit cartésien qui multiplie le volume des données de façon exponentielle et sollicite inutilement le moteur. Avec 1 000 clients et 10 000 commandes, ce scénario produit 10 millions de lignes sans valeur informative. Il faut toujours vérifier la présence d’une condition explicite avant d’exécuter toute instruction de liaison.