Skip to main content

Jointures SQL : guide complet sur les types, les différences et les cas d'utilisation de chacune d'entre elles

Les jointures SQL constituent l'une des fonctionnalités les plus puissantes — et les plus mal comprises — des bases de données relationnelles. Ce guide traite en détail chaque type de jointure, à l'aide d'exemples concrets, de tableaux comparatifs et de conseils clairs sur les situations dans lesquelles il convient d'utiliser chacune d'entre elles.

19 min read
Jointures SQL : guide complet sur les types, les différences et les cas d'utilisation de chacune d'entre elles

Les jointures sont le mécanisme qui donne leur nom aux bases de données relationnelles. L’intérêt de séparer les données en tables distinctes et normalisées réside précisément dans la possibilité de les combiner à la demande — en extrayant exactement la partie des données liées dont vous avez besoin, sous la forme qui vous convient. Une compréhension approfondie des jointures est indispensable pour quiconque travaille sérieusement avec SQL. C’est cette compétence qui fait la différence entre une requête qui fonctionne et une requête qui fonctionne correctement.

Ce guide couvre tous les types de jointures standard — INNER, LEFT, RIGHT, FULL OUTER, CROSS et SELF — à l’aide d’exemples concrets, de tableaux de résultats et de conseils clairs sur les cas où chacune est appropriée. À la fin de ce guide, vous devriez être capable d’analyser un problème lié aux données et de déterminer immédiatement quelle jointure, ou combinaison de jointures, vous donnera la bonne réponse.

Le schéma d’exemple

Tous les exemples de ce guide utilisent les deux mêmes tables, ce qui permet des comparaisons claires et directement comparables.

clients

customer_id nom ville
1 Alice Nguyen Sydney
2 Bob Martins Melbourne
3 Carol White Brisbane
4 David Kim Sydney

commandes

id_commande id_client produit montant
101 1 Ordinateur portable 1 200,00
102 1 Souris 45,00
103 2 Clavier 89,00
104 5 Écran 399,00

Quelques points à noter délibérément : le client 3 (Carol) et le client 4 (David) n’ont aucune commande. La commande 104 fait référence à un customer_id 5, qui n’existe pas dans la table des clients. Ce sont ces cas limites qui donnent tout leur sens aux différents types de jointures.

INNER JOIN

Une jointure INNER JOIN ne renvoie que les lignes pour lesquelles il existe une valeur correspondante dans les deux tables. Si une ligne de la table de gauche n’a pas de correspondance dans la table de droite, elle est exclue. Si une ligne de la table de droite n’a pas de correspondance dans la table de gauche, elle est également exclue.

SELECT
c.customer_id,
c.name,
o.order_id,
o.product,
o.amount
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id;

Résultat :

customer_id name order_id product amount
1 Alice Nguyen 101 Ordinateur portable 1 200,00
1 Alice Nguyen 102 Souris 45,00
2 Bob Martins 103 Clavier 89,00

Remarquez ce qui manque : Carol et David (clients n° 3 et 4) n’apparaissent pas car ils n’ont aucune commande correspondante. La commande n° 104 n’apparaît pas car l’identifiant client customer_id 5 n’existe pas dans la table des clients. L’INNER JOIN correspond à l’intersection : seules les lignes présentant une correspondance des deux côtés sont conservées.

Quand l’utiliser : l’INNER JOIN est le bon choix lorsque vous ne vous intéressez qu’aux enregistrements ayant une relation dans les deux tables. Établir des rapports sur les clients ayant passé des commandes, les produits vendus, les employés affectés à des projets — tout scénario où les lignes sans correspondance ne sont pas pertinentes pour la question.

Le piège : si vous utilisez un INNER JOIN alors que vous avez en réalité besoin de tous les enregistrements d’un côté, vous perdrez des données sans vous en rendre compte. La requête s’exécute sans erreur, mais les résultats sont incomplets. C’est l’une des causes les plus courantes de rapports erronés en SQL.


LEFT JOIN (LEFT OUTER JOIN)

Un LEFT JOIN renvoie toutes les lignes de la table de gauche, ainsi que les lignes correspondantes de la table de droite. Lorsqu’il n’y a pas de correspondance dans la table de droite, les colonnes de droite sont renseignées avec la valeur NULL.

SELECT
c.customer_id,
c.name,
o.order_id,
o.product,
o.amount
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id;

Résultat :

customer_id name order_id product amount
1 Alice Nguyen 101 Ordinateur portable 1 200,00
1 Alice Nguyen 102 Souris 45,00
2 Bob Martins 103 Clavier 89,00
3 Carol White NULL NULL NULL
4 David Kim NULL NULL NULL

Carol et David apparaissent désormais, avec des valeurs NULL pour les colonnes de commande. La commande n° 104 n'apparaît toujours pas : elle n'a pas de client correspondant, et la table de gauche ici est celle des clients, et non celle des commandes.

Quand l’utiliser : LEFT JOIN est la jointure la plus couramment utilisée après INNER JOIN. Utilisez-la chaque fois que vous souhaitez obtenir tous les enregistrements de la table principale (de gauche), qu’ils aient ou non une correspondance dans la table secondaire (de droite). Listes de clients avec leur dernière commande (ou NULL s’ils n’ont jamais commandé), produits avec leur niveau de stock actuel (ou NULL s’ils ne sont pas encore en stock), utilisateurs avec leurs données de profil (ou NULL si le profil n’a pas encore été créé).

Recherche de lignes sans correspondance : LEFT JOIN combiné à une clause WHERE filtrant les valeurs NULL est la méthode standard pour trouver les enregistrements sans correspondance :

-- Trouver les clients qui n’ont jamais passé de commande
SELECT c.customer_id, c.name
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;

Résultat :

customer_id name
3 Carol White
4 David Kim

Cette approche est plus claire et souvent plus performante que l’utilisation de sous-requêtes NOT IN ou NOT EXISTS pour la même tâche.


JOIN DROIT (RIGHT OUTER JOIN)

Un RIGHT JOIN est l’image miroir d’un LEFT JOIN. Il renvoie toutes les lignes de la table de droite, ainsi que toutes les lignes correspondantes de la table de gauche. Lorsqu’il n’y a pas de correspondance dans la table de gauche, les colonnes de gauche sont NULL.

SELECT
c.customer_id,
c.name,
o.order_id,
o.product,
o.amount
FROM customers c
RIGHT JOIN orders o ON c.customer_id = o.customer_id;

Résultat :

customer_id name order_id product amount
1 Alice Nguyen 101 Ordinateur portable 1 200,00
1 Alice Nguyen 102 Souris 45,00
2 Bob Martins 103 Clavier 89,00
NULL NULL 104 Écran 399,00

L'ordre n° 104 apparaît désormais, avec des valeurs NULL dans les colonnes client car l'identifiant customer_id 5 n'existe pas. Carol et David ont disparu : ils n'ont pas de commandes, et c'est la table de droite (commandes) qui détermine le résultat.

Quand l’utiliser : Le RIGHT JOIN est moins courant dans la pratique, pour une raison simple : tout RIGHT JOIN peut être réécrit sous forme de LEFT JOIN en inversant l’ordre des tables. La plupart des développeurs trouvent le LEFT JOIN plus lisible car il correspond au sens naturel de lecture — « donne-moi tout ce qui se trouve dans cette table, plus tout ce qui correspond dans celle-là ».

-- Ces deux requêtes renvoient des résultats identiques :

-- RIGHT JOIN
SELECT c.nom, o.produit
FROM clients c
RIGHT JOIN orders o ON c.customer_id = o.customer_id;

-- LEFT JOIN équivalent (style recommandé)
SELECT c.name, o.product
FROM orders o
LEFT JOIN customers c ON c.customer_id = o.customer_id;

Utilisez le RIGHT JOIN lorsque la requête est plus lisible ainsi, ou lorsque vous travaillez sur une base de code qui l'utilise de manière cohérente. Ne l'utilisez jamais simplement parce que vous avez appris qu'il existait.


FULL OUTER JOIN

Un FULL OUTER JOIN renvoie toutes les lignes des deux tables. Lorsqu’il y a une correspondance, les colonnes des deux côtés sont renseignées. Lorsqu’il n’y a pas de correspondance d’un côté ou de l’autre, les colonnes du côté sans correspondance prennent la valeur NULL.

SELECT
c.customer_id,
c.name,
o.order_id,
o.product,
o.amount
FROM customers c
FULL OUTER JOIN orders o ON c.customer_id = o.customer_id;

Résultat :

customer_id name order_id product amount
1 Alice Nguyen 101 Ordinateur portable 1 200,00
1 Alice Nguyen 102 Souris 45,00
2 Bob Martins 103 Clavier 89,00
3 Carol White NULL NULL NULL
4 David Kim NULL NULL NULL
NULL NULL 104 Écran 399,00

Toutes les lignes des deux tables apparaissent. Les lignes correspondantes sont jointes. Les lignes non correspondantes de l’un ou l’autre côté apparaissent avec des valeurs NULL de l’autre côté.

Quand l’utiliser : la jointure FULL OUTER JOIN est le bon choix lorsque vous avez besoin de voir simultanément tout ce qui existe — correspondances et non-correspondances — des deux côtés. Rapprochement de données entre deux systèmes, recherche de divergences entre une source et une destination, audit des éléments présents dans une table mais pas dans l’autre. Elle est moins courante que les jointures INNER ou LEFT JOIN, mais indispensable lorsque vous en avez besoin.

Remarque concernant MySQL : MySQL ne prend pas en charge nativement la syntaxe FULL OUTER JOIN. La solution standard consiste à combiner (UNION) un LEFT JOIN et un RIGHT JOIN :

SELECT c.customer_id, c.name, o.order_id, o.product
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id

UNION

SELECT c.customer_id, c.name, o.order_id, o.product
FROM customers c
RIGHT JOIN orders o ON c.customer_id = o.customer_id;

PostgreSQL, SQL Server et la plupart des autres bases de données prennent directement en charge le FULL OUTER JOIN.

Extreme close-up of programming code on a screen showing various technical elements


CROSS JOIN

Une jointure croisée (CROSS JOIN) renvoie le produit cartésien des deux tables : chaque ligne de la table de gauche est combinée avec chaque ligne de la table de droite. Il n'y a pas de condition ON, car toutes les combinaisons sont renvoyées, quelle que soit la relation entre les tables.

SELECT
c.nom,
o.produit
FROM clients c
CROSS JOIN commandes o;

Avec 4 clients et 4 commandes, cela renvoie 4 × 4 = 16 lignes :

nom produit
Alice Nguyen Ordinateur portable
Alice Nguyen Souris
Alice Nguyen Clavier
Alice Nguyen Écran
Bob Martins Ordinateur portable
Bob Martins Souris
... ...

Le résultat complet comporte 16 lignes. Avec 100 lignes × 100 lignes, cela fait 10 000. Avec 1 000 × 1 000, cela fait 1 000 000. Les jointures croisées (CROSS JOIN) croissent de manière exponentielle ; elles doivent donc être utilisées avec prudence.

Quand l’utiliser : le CROSS JOIN présente de véritables cas d’utilisation. Générer toutes les combinaisons de tailles et de couleurs pour un catalogue de produits. Créer une table de dimension de dates en croisant une liste d’années avec une liste de jours. Construire des données de test nécessitant toutes les permutations. Associer chaque commercial à chaque région pour une matrice de couverture.

Le CROSS JOIN accidentel : L’une des erreurs SQL les plus dangereuses est un CROSS JOIN accidentel causé par une condition JOIN manquante ou incorrecte. Si vous oubliez la clause ON ou si vous effectuez accidentellement une jointure sur une condition qui s’évalue toujours à vrai, vous pouvez renvoyer des millions de lignes à partir de deux tables relativement petites. Vérifiez toujours le nombre de lignes lorsque vous travaillez avec plusieurs jointures.


SELF JOIN

Un SELF JOIN n’est pas un type de jointure distinct dans la syntaxe SQL : il s’agit de toute jointure où une table est jointe à elle-même. Vous utilisez une jointure standard (INNER, LEFT ou autre), mais les deux côtés de la jointure font référence à la même table avec des alias différents.

Le cas d’utilisation classique concerne les données hiérarchiques ou récursives : une table employees où chaque ligne comporte un champ manager_id qui fait référence à un autre champ employee_id dans la même table.

Prenons l'exemple de cette table employees :

employees

employee_id name manager_id
1 Sarah Chen NULL
2 James Okafor 1
3 Maria Lopez 1
4 Tom Brennan 2
5 Yuki Tanaka 2

Sarah est la PDG et n’a pas de responsable. James et Maria sont sous les ordres de Sarah. Tom et Yuki sont sous les ordres de James.

SELECT
e.nom AS employé,
m.nom AS responsable
FROM employés e
LEFT JOIN employés m ON e.id_responsable = m.id_employé;

Résultat :

employé responsable
Sarah Chen NULL
James Okafor Sarah Chen
Maria Lopez Sarah Chen
Tom Brennan James Okafor
Yuki Tanaka James Okafor

Nous utilisons LEFT JOIN afin que Sarah (qui n’a pas de responsable) apparaisse tout de même dans les résultats avec un responsable NULL, plutôt que d’être exclue par un INNER JOIN.

Autres cas d’utilisation de l’auto-jointure : rechercher des enregistrements en double dans une table, identifier les lignes qui partagent une valeur avec une autre ligne, comparer une ligne à des lignes adjacentes dans une série chronologique, trouver toutes les paires d’éléments partageant une même catégorie.


Comparaison de tous les types de jointures

Type de jointure Lignes non appariées à gauche Lignes non appariées à droite À utiliser lorsque
INNER JOIN Exclues Exclues Vous ne souhaitez que les lignes présentant une correspondance des deux côtés
LEFT JOIN Inclues (NULL) Exclues Vous souhaitez toutes les lignes de gauche, avec ou sans correspondance
RIGHT JOIN Exclues Inclues (NULL) Vous souhaitez toutes les lignes de droite, avec ou sans correspondance
FULL OUTER JOIN Inclues (NULL) Inclues (NULL) Vous souhaitez toutes les lignes des deux tables
CROSS JOIN N/A (aucune condition) N/A (aucune condition) Vous avez besoin de toutes les combinaisons de lignes des deux tables
SELF JOIN Dépend du type de jointure utilisé Dépend du type de jointure utilisé Vous devez relier des lignes au sein d’une même table

Joindre plus de deux tables

Les requêtes réelles joignent fréquemment trois, quatre tables ou plus. Chaque jointure supplémentaire étend l’ensemble de résultats de la jointure précédente. L’ordre est important : chaque JOIN opère sur le résultat de tout ce qui se trouve à sa gauche.

SELECT
c.name,
o.order_id,
o.product,
p.category,
p.supplier
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
INNER JOIN products p ON o.product_id = p.product_id
LEFT JOIN suppliers s ON p.supplier_id = s.supplier_id;

Quelques principes permettant de gérer efficacement les jointures multi-tables :

Commencez par la jointure la plus sélective. Si une jointure réduit considérablement le nombre de lignes, la placer en premier permet aux jointures suivantes de s’appliquer à un nombre de lignes plus restreint. Cela peut avoir un impact significatif sur les performances avec des tables volumineuses.

Choisissez soigneusement les types de jointure. Chaque jointure d’une chaîne est une décision indépendante. Vous pouvez utiliser une jointure INNER JOIN entre la table customers et la table orders (vous ne souhaitez que les clients ayant passé commande), mais une jointure LEFT JOIN entre la table orders et la table shipments (vous souhaitez toutes les commandes, y compris celles qui n’ont pas encore été expédiées).

Utilisez des alias de manière cohérente. À partir de trois tables, les noms de colonnes peuvent entrer en conflit. Attribuez toujours un alias à vos tables et ajoutez un préfixe à chaque référence de colonne. c.name ne prête pas à confusion ; name dans une jointure à quatre tables constitue un risque pour la maintenance.

Vérifiez le nombre de lignes au fur et à mesure. Lorsque vous construisez une requête de jointure complexe, ajoutez chaque table progressivement et vérifiez le nombre de lignes à chaque étape. Une augmentation inattendue du nombre de lignes signifie généralement qu’une condition de jointure est erronée ou manquante.


Considérations relatives aux performances des jointures

C’est au niveau des jointures que les performances SQL se confirment ou s’effondrent. Quelques principes méritent d’être compris, quel que soit le moteur de base de données que vous utilisez.

Les index sur les colonnes de jointure sont essentiels. Lorsque vous effectuez une jointure sur customer_id, la base de données doit rechercher les lignes correspondantes. Sans index, elle parcourt l’intégralité de la table à chaque recherche. Avec un index, elle accède directement aux lignes correspondantes. Pour toute colonne sur laquelle vous effectuez régulièrement des jointures, assurez-vous qu’elle soit indexée : il s’agit de la mesure d’optimisation des performances la plus efficace pour les requêtes comportant de nombreuses jointures.

Filtrer en amont réduit le coût des jointures. Placer les conditions WHERE le plus tôt possible — ou utiliser des sous-requêtes et des CTE pour pré-filtrer — permet à la jointure de porter sur moins de lignes. Une jointure entre 10 000 lignes et 500 lignes est bien moins coûteuse qu’une jointure entre 10 000 lignes et 50 000 lignes, même si le résultat final filtré est de la même taille.

EXPLAIN est votre allié. Tous les principaux moteurs de base de données prennent en charge EXPLAIN (ou EXPLAIN ANALYZE dans PostgreSQL) pour afficher le plan d’exécution de la requête. Si une requête de jointure est lente, exécutez d’abord EXPLAIN. Cela vous indiquera si des index sont utilisés, où se produisent des balayages séquentiels et quels sont les nombres estimés de lignes à chaque étape. Apprendre à lire la sortie d’EXPLAIN est un atout majeur pour optimiser les performances SQL.

Méfiez-vous du fan-out. Si, dans une jointure, le côté droit comporte plusieurs lignes correspondant à chaque ligne du côté gauche, le jeu de résultats comportera plus de lignes que l’une ou l’autre des tables d’entrée. Il s’agit d’un comportement normal, mais cela peut entraîner des agrégats gonflés si vous ne faites pas attention. La fonction COUNT(*) appliquée à un jeu de résultats issu d’une jointure compte les lignes jointes, et non les lignes d’origine du côté gauche. Utilisez COUNT(DISTINCT customer_id) ou effectuez l’agrégation avant la jointure lorsque cela est important.


Erreurs courantes et comment les éviter

Utiliser INNER JOIN alors qu’un LEFT JOIN est nécessaire. La requête produit des résultats qui semblent plausibles, mais des lignes sont omises sans que cela soit signalé. Posez-vous toujours la question suivante : les lignes sans correspondance doivent-elles tout de même apparaître dans mes résultats ? Si oui, utilisez LEFT JOIN.

Filtrer sur une colonne NULL après un LEFT JOIN. Si vous effectuez un LEFT JOIN puis ajoutez WHERE o.status = 'shipped', vous avez en fait transformé le LEFT JOIN en INNER JOIN : les lignes où o.status est NULL (c'est-à-dire les lignes de gauche sans correspondance) seront exclues. Filtrez sur les colonnes de droite dans la clause ON, et non dans la clause WHERE, si vous souhaitez conserver les lignes de gauche sans correspondance.

-- INCORRECT : transforme le LEFT JOIN en un comportement de type INNER JOIN
SELECT c.name, o.order_id
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.status = 'shipped';  -- exclut les lignes NULL

-- CORRECT : conserve les clients non appariés
SELECT c.name, o.order_id
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
AND o.status = 'shipped';

Effectuer une jointure sur une colonne non unique sans en comprendre les conséquences. Si vous effectuez une jointure sur une colonne comportant des valeurs en double du côté droit, chaque ligne de gauche correspondra à plusieurs lignes de droite et le jeu de résultats se multipliera. C’est parfois ce que vous souhaitez ; mais souvent, ce n’est pas le cas. Connaissez la cardinalité de vos données avant de supposer qu’une jointure est de type 1:1.

Oublier de gérer les valeurs NULL dans les agrégats. SUM(o.amount) sur le résultat d’une jointure LEFT JOIN ignorera correctement les valeurs NULL, mais AVG(o.amount) les ignorera également — ce qui signifie que la moyenne est calculée sur les clients ayant passé des commandes, et non sur l’ensemble des clients. COALESCE(o.amount, 0) est souvent la bonne approche lorsque les valeurs NULL doivent être traitées comme des zéros.


Référence rapide : choisir la bonne jointure

Lorsque vous vous apprêtez à écrire une requête de jointure, posez-vous ces questions dans l’ordre :

  1. Ai-je besoin des lignes de la table de gauche même si elles n’ont pas de correspondance dans la table de droite ? Si oui → LEFT JOIN.
  2. Ai-je besoin des lignes de la table de droite même si elles n’ont pas de correspondance dans la table de gauche ? Si oui → RIGHT JOIN (ou inversez les tables et utilisez LEFT JOIN).
  3. Ai-je besoin des lignes sans correspondance des deux côtés ? Si oui → FULL OUTER JOIN.
  4. Est-ce que je ne m’intéresse qu’aux lignes qui ont une correspondance des deux côtés ? Si oui → INNER JOIN.
  5. Ai-je besoin de toutes les combinaisons de lignes, quelle que soit la relation entre elles ? Si oui → CROSS JOIN (à utiliser avec prudence).
  6. Est-ce que je relie des lignes au sein d’une même table ? Si oui → SELF JOIN en utilisant l’un des types ci-dessus.

Les jointures récompensent une réflexion mûrement pesée. Le type que vous choisissez détermine ce que vous souhaitez qu’il advienne des lignes sans correspondance. Prenez la bonne décision et le reste de la requête s’enchaînera naturellement.