Comprendre les JOINs SQL : tous les types avec exercices
Maîtrisez les JOINs SQL avec schémas clairs, exemples pratiques et exercices. INNER, LEFT, RIGHT, FULL OUTER JOIN et plus.
Thomas Leroy
Les JOINs sont le fondement de SQL. Si vous ne maîtrisez qu'un seul concept pour votre entretien technique, ce doit être celui-ci. Dans tous les entretiens data analyst, data engineer ou data scientist, les questions sur les JOINs arrivent en premier — et elles éliminent beaucoup de candidats.
Thomas Leroy vous propose ici un guide complet avec des exemples concrets, des schémas clairs et des exercices corrigés pour que le sujet soit verrouillé le jour de l'entretien.
📌 Ce qu'il faut retenir
INNER JOIN ne retourne que les lignes avec correspondances dans les deux tables
LEFT JOIN conserve toutes les lignes de gauche, même sans correspondance
RIGHT JOIN conserve toutes les lignes de droite (rarement utilisé)
FULL OUTER JOIN combine toutes les lignes des deux tables
Le piège WHERE + LEFT JOIN transforme silencieusement un LEFT JOIN en INNER JOIN
Toujours vérifier les NULL et les valeurs orphelines avant de joindre
Les tables d'exemple
Pour tous les exemples de cet article, nous utiliserons deux tables :
Table employes :
id
nom
departement_id
1
Alice
10
2
Bob
20
3
Charlie
30
4
Diana
NULL
Table departements :
id
nom_departement
10
Marketing
20
Tech
40
Finance
Remarquez les cas spéciaux : Charlie a un departement_id = 30 qui n'existe pas dans departements. Diana a un departement_id NULL. Le département Finance (id 40) n'a aucun employé. Ces cas sont précisément ceux que les recruteurs testent.
INNER JOIN : l'intersection
INNER JOIN renvoie uniquement les lignes qui ont une correspondance dans les deux tables.
SELECT
e.nom,
d.nom_departement
FROM employes e
INNERJOIN departements d ON e.departement_id = d.id;
<div style="overflow-x:auto;margin:20px 0;"><table><thead style="background-color:#0F172A;color:white;"><tr><th style="padding:12px 16px;text-align:left">nom</th><th style="padding:12px 16px;text-align:left">nom_departement</th></tr></thead><tbody><tr style="background:#f8fafc"><td style="padding:12px 16px">Alice</td><td style="padding:12px 16px">Marketing</td></tr><tr><td style="padding:12px 16px">Bob</td><td style="padding:12px 16px">Tech</td></tr></tbody></table></div>
Seuls Alice et Bob apparaissent : ce sont les seuls employés dont le `departement_id` correspond à un `id` dans `departements`.
- Charlie (departement_id =30) : pas de correspondance → exclu
- Diana (departement_id =NULL) : pas de correspondance → exclue
- Finance (id =40) : aucun employé → exclu
### Quand utiliser INNERJOIN
Utilisez INNERJOIN quand vous voulez **uniquement les lignes qui matchent des deux côtés**. C'est le JOIN le plus courant et le plus performant.
### Exemple concret : rapport de ventes par région
```sql
-- Seulement les vendeurs assignés à une région avec leurs chiffres
SELECT
v.nom_vendeur,
r.nom_region,
SUM(v.montant_vente) as total_ventes
FROM vendeurs v
INNER JOIN regions r ON v.region_id = r.id
WHERE v.date_vente >= '2024-01-01'
GROUP BY v.nom_vendeur, r.nom_region;
Cette requête exclut automatiquement les vendeurs sans région assignée et les régions sans vendeur actif.
## LEFT JOIN : toutes les lignes de gauche
`LEFT JOIN` (ou `LEFT OUTER JOIN`) renvoie **toutes les lignes de la table de gauche**, avec les données de la table de droite quand elles existent. Quand il n'y a pas de correspondance, les colonnes de droite sont remplies avec NULL.
```sqlSELECT
e.nom,
d.nom_departement
FROM employes e
LEFTJOIN departements d ON e.departement_id = d.id;
nom
nom_departement
Alice
Marketing
Bob
Tech
Charlie
NULL
Diana
NULL
Tous les employés apparaissent. Charlie et Diana n'ont pas de correspondance, donc nom_departement est NULL.
⚠️ Attention
Ajouter une condition WHERE sur une colonne de la table de droite annule l'effet du LEFT JOIN et le transforme silencieusement en INNER JOIN. Les lignes où la colonne de droite est NULL (c'est-à-dire les lignes sans correspondance) sont éliminées par le filtre. Ce piège revient dans la quasi-totalité des entretiens SQL.
Le piège du WHERE avec LEFT JOIN
Un piège classique en entretien :
-- PIÈGE : ce LEFT JOIN se comporte comme un INNER JOINSELECT e.nom, d.nom_departement
FROM employes e
LEFTJOIN departements d ON e.departement_id = d.id
WHERE d.nom_departement ='Marketing';
Le WHERE filtre après le JOIN, donc il élimine les lignes où nom_departement est NULL. Pour filtrer sur la table de droite tout en conservant le LEFT JOIN, utilisez la condition dans le ON :
-- Correct : filtre dans le ONSELECT e.nom, d.nom_departement
FROM employes e
LEFTJOIN departements d
ON e.departement_id = d.id
AND d.nom_departement ='Marketing';
nom
nom_departement
Alice
Marketing
Bob
NULL
Charlie
NULL
Diana
NULL
Trouver les lignes sans correspondance
Un cas d'usage majeur du LEFT JOIN : identifier les lignes orphelines. Ce pattern revient constamment dans les entretiens data analyst.
-- Employés sans département valideSELECT e.nom
FROM employes e
LEFTJOIN departements d ON e.departement_id = d.id
WHERE d.id ISNULL;
nom
Charlie
Diana
Ce pattern « LEFT JOIN + WHERE IS NULL » est appelé anti-join et revient très souvent en entretien.
Exemple concret : audit de données clients
-- Clients sans commande depuis 6 mois (potentiel churn)SELECT
c.nom_client,
c.email,
c.date_inscription,
MAX(co.date_commande) as derniere_commande
FROM clients c
LEFTJOIN commandes co ON c.id = co.client_id
AND co.date_commande >= DATE_SUB(NOW(), INTERVAL6MONTH)
WHERE co.id ISNULLAND c.date_inscription < DATE_SUB(NOW(), INTERVAL6MONTH);
RIGHT JOIN : toutes les lignes de droite
RIGHT JOIN est le miroir du LEFT JOIN : il conserve toutes les lignes de la table de droite.
SELECT
e.nom,
d.nom_departement
FROM employes e
RIGHTJOIN departements d ON e.departement_id = d.id;
nom
nom_departement
Alice
Marketing
Bob
Tech
NULL
Finance
Le département Finance apparaît maintenant, même sans employé. En revanche, Charlie et Diana disparaissent car ils n'ont pas de correspondance dans la table de droite.
En pratique, le RIGHT JOIN est rarement utilisé. On préfère inverser les tables et utiliser un LEFT JOIN pour une meilleure lisibilité.
FULL OUTER JOIN : l'union complète
FULL OUTER JOIN renvoie toutes les lignes des deux tables, avec NULL là où il n'y a pas de correspondance.
SELECT
e.nom,
d.nom_departement
FROM employes e
FULLOUTERJOIN departements d ON e.departement_id = d.id;
nom
nom_departement
Alice
Marketing
Bob
Tech
Charlie
NULL
Diana
NULL
NULL
Finance
Toutes les lignes sont présentes. C'est le JOIN le plus inclusif.
💡 Bon à savoir
MySQL ne supporte pas FULL OUTER JOIN nativement. Il faut simuler avec un UNION de LEFT et RIGHT JOIN. PostgreSQL et SQL Server supportent FULL OUTER JOIN directement.
-- Simulation FULL OUTER JOIN en MySQLSELECT e.nom, d.nom_departement
FROM employes e
LEFTJOIN departements d ON e.departement_id = d.id
UNIONSELECT e.nom, d.nom_departement
FROM employes e
RIGHTJOIN departements d ON e.departement_id = d.id;
Exemple concret : réconciliation comptable
-- Comparer factures émises vs paiements reçusSELECTCOALESCE(f.numero_facture, p.reference_facture) as facture,
f.montant_facture,
p.montant_paye,
CASEWHEN f.numero_facture ISNULLTHEN'Paiement sans facture'WHEN p.reference_facture ISNULLTHEN'Facture impayée'WHEN f.montant_facture = p.montant_paye THEN'OK'ELSE'Différence montant'ENDas statut
FROM factures f
FULLOUTERJOIN paiements p ON f.numero_facture = p.reference_facture;
CROSS JOIN : le produit cartésien
CROSS JOIN produit le produit cartésien : chaque ligne de la table de gauche est combinée avec chaque ligne de la table de droite.
SELECT e.nom, d.nom_departement
FROM employes e
CROSSJOIN departements d;
Avec 4 employés et 3 départements, vous obtenez 12 lignes. Le CROSS JOIN est utile pour générer des combinaisons (par exemple : tous les mois × tous les produits pour un rapport complet).
Exemple concret : génération de planning
-- Générer toutes les créneaux possibles pour les entretiensSELECT
c.nom_candidat,
h.creneau_heure,
s.nom_salle
FROM candidats c
CROSSJOIN horaires_dispo h
CROSSJOIN salles s
WHERE c.statut ='CONVOQUE'AND h.date_creneau ='2024-03-15'AND s.capacite >=2ORDERBY c.nom_candidat, h.creneau_heure;
⚠️ Attention
Le CROSS JOIN peut générer énormément de lignes très rapidement. Avec deux tables de 1000 lignes chacune, vous obtenez 1 million de lignes. Utilisez toujours des filtres WHERE appropriés.
SELF JOIN : une table avec elle-même
Le SELF JOIN consiste à joindre une table avec elle-même. C'est indispensable pour les structures hiérarchiques.
-- Table employes avec manager_idSELECT
e.nom AS employe,
m.nom AS manager
FROM employes e
LEFTJOIN employes m ON e.manager_id = m.id;
Exemple concret : hiérarchie managériale
-- Afficher tous les employés avec leur chaîne hiérarchiqueWITHRECURSIVE hierarchy AS (
-- Niveau 0 : PDG (pas de manager)SELECT id, nom, manager_id, nom as chemin, 0as niveau
FROM employes
WHERE manager_id ISNULLUNIONALL-- Niveaux suivantsSELECT e.id, e.nom, e.manager_id,
CONCAT(h.chemin, ' > ', e.nom) as chemin,
h.niveau +1FROM employes e
INNERJOIN hierarchy h ON e.manager_id = h.id
)
SELECT nom, chemin, niveau
FROM hierarchy
ORDERBY niveau, nom;
Autre cas classique en entretien : trouver les paires de clients dans la même ville.
SELECT
c1.nom AS client_1,
c2.nom AS client_2,
c1.ville
FROM clients c1
INNERJOIN clients c2
ON c1.ville = c2.ville
AND c1.id < c2.id; -- évite les doublons et auto-jointures
Joindre plus de deux tables
En entretien, les requêtes impliquent souvent 3 ou 4 tables. La logique est la même — on enchaîne les JOINs :
SELECT
e.nom AS employe,
d.nom_departement,
p.titre AS projet
FROM employes e
INNERJOIN departements d ON e.departement_id = d.id
INNERJOIN projets p ON e.id = p.employe_id;
Règle : chaque JOIN se fait entre une table déjà dans la requête et une nouvelle table. L'ordre des JOINs peut affecter les performances, mais pas le résultat (l'optimiseur SQL se charge généralement de réorganiser).
Exemple complexe : rapport de performance commercial
SELECT
v.nom_vendeur,
e.nom_equipe,
r.nom_region,
p.nom_produit,
SUM(c.montant) as ca_total,
COUNT(c.id) as nb_commandes,
AVG(c.montant) as panier_moyen
FROM vendeurs v
INNERJOIN equipes e ON v.equipe_id = e.id
INNERJOIN regions r ON v.region_id = r.id
LEFTJOIN commandes c ON v.id = c.vendeur_id
AND c.date_commande >='2024-01-01'LEFTJOIN produits p ON c.produit_id = p.id
WHERE v.statut ='ACTIF'GROUPBY v.id, v.nom_vendeur, e.nom_equipe, r.nom_region, p.nom_produit
HAVING ca_total >10000OR ca_total ISNULLORDERBY ca_total DESCNULLS LAST;
Les conditions de jointure composées
On peut joindre sur plusieurs colonnes :
SELECT*FROM commandes c
INNERJOIN livraisons l
ON c.commande_id = l.commande_id
AND c.entrepot_id = l.entrepot_id;
On peut aussi utiliser des opérateurs de comparaison autres que = (non-equi join) :
-- Trouver les employés embauchés pendant une période promotionnelleSELECT e.nom, p.nom_promo
FROM employes e
INNERJOIN promotions p
ON e.date_embauche BETWEEN p.date_debut AND p.date_fin;
Exemple avancé : jointure temporelle
-- Associer chaque vente au taux de change valide à cette dateSELECT
v.date_vente,
v.montant_local,
v.devise,
tc.taux_change,
v.montant_local * tc.taux_change as montant_eur
FROM ventes v
INNERJOIN taux_change tc ON v.devise = tc.devise
AND v.date_vente >= tc.date_debut
AND v.date_vente <COALESCE(tc.date_fin, '9999-12-31');
Erreurs fréquentes à éviter
1. Oublier les cas NULL
-- ERREUR : ne trouve pas les employés avec departement_id NULLSELECTCOUNT(*) FROM employes WHERE departement_id <>999;
-- CORRECT : inclure explicitement les NULLSELECTCOUNT(*) FROM employes
WHERE departement_id <>999OR departement_id ISNULL;
2. Confondre WHERE et HAVING avec les JOINs
-- ERREUR : HAVING sans GROUP BY avec un JOINSELECT e.nom, d.nom_departement
FROM employes e
LEFTJOIN departements d ON e.departement_id = d.id
HAVING d.nom_departement ISNOT NULL;
-- CORRECT : utiliser WHERESELECT e.nom, d.nom_departement
FROM employes e
LEFTJOIN departements d ON e.departement_id = d.id
WHERE d.nom_departement ISNOT NULL;
3. Multiplications de lignes non intentionnelles
-- PROBLÈME : si un employé a plusieurs projets ET plusieurs formations,-- on obtient le produit cartésien (3 projets × 2 formations = 6 lignes)SELECT e.nom, p.nom_projet, f.nom_formation
FROM employes e
LEFTJOIN projets p ON e.id = p.employe_id
LEFTJOIN formations f ON e.id = f.employe_id;
-- SOLUTION : séparer en sous-requêtes ou utiliser des agrégationsSELECT
e.nom,
STRING_AGG(DISTINCT p.nom_projet, ', ') as projets,
STRING_AGG(DISTINCT f.nom_formation, ', ') as formations
FROM employes e
LEFTJOIN projets p ON e.id = p.employe_id
LEFTJOIN formations f ON e.id = f.employe_id
GROUPBY e.id, e.nom;
4. Ignorer la casse dans les comparaisons texte
💡 Bon à savoir
Dans certains SGBD, les comparaisons de texte sont sensibles à la casse. Utilisez UPPER() ou LOWER() pour des jointures robustes sur des champs texte.
-- Jointure robuste sur des champs texteSELECT e.nom, d.nom_departement
FROM employes e
INNERJOIN departements d ONUPPER(e.code_dept) =UPPER(d.code);
5. Jointure sur des types de données incompatibles
-- ERREUR : joindre un VARCHAR avec un INTSELECT*FROM produits p
INNERJOIN categories c ON p.categorie_nom = c.id;
-- CORRECT : convertir ou utiliser la bonne colonneSELECT*FROM produits p
INNERJOIN categories c ON p.categorie_id = c.id;
Spécificités par SGBD
MySQL
Pas de FULL OUTER JOIN natif → utiliser UNION
Support des jointures STRAIGHT_JOIN pour forcer l'ordre
Optimiseur moins sophistiqué que PostgreSQL/SQL Server
Comparaisons de texte insensibles à la casse par défaut (dépend du collation)
PostgreSQL
Excellent support de tous les types de JOINs
LATERAL JOINs pour des sous-requêtes corrélées complexes
Optimiseur très performant pour les requêtes multi-tables
Extensions PostGIS pour des jointures spatiales avancées
SQL Server
Support complet des JOINs standards
CROSS APPLY / OUTER APPLY comme alternative aux LATERAL JOINs
Plans d'exécution très détaillés pour optimiser les performances
Index hints disponibles pour contrôler les stratégies de jointure
Oracle
Support complet + syntaxe propriétaire avec (+) pour les outer joins
Hints de jointure (/*+ USE_NL /, /+ USE_HASH */) pour contrôler l'optimiseur
Partitioned joins pour les très gros volumes
Materialized views pour optimiser les jointures fréquentes
SQLite
Support limité : pas de FULL OUTER JOIN ni de RIGHT JOIN
Optimiseur simple mais efficace pour les petites bases
Jointures performantes sur les index B-tree
Exemples nominatifs par scénario métier
Marco, développeur e-commerce chez Zalando
Marco doit analyser les abandons de panier. Il utilise un LEFT JOIN pour conserver tous les paniers, même ceux sans commande finalisée :
-- Analyse des abandons de panierSELECT
p.user_id,
p.session_id,
COUNT(pi.product_id) as nb_produits_panier,
SUM(pi.price) as valeur_panier,
CASEWHEN c.order_id ISNULLTHEN'ABANDON'ELSE'CONVERTI'ENDas statut
FROM panier p
LEFTJOIN panier_items pi ON p.id = pi.panier_id
LEFTJOIN commandes c ON p.id = c.panier_id
WHERE p.created_at >='2024-01-01'GROUPBY p.id, p.user_id, p.session_id, c.order_id
HAVING nb_produits_panier >0ORDERBY valeur_panier DESC;
Sophie, data analyst dans une banque française
Sophie analyse les comptes clients avec leurs produits souscrits. Elle utilise un FULL OUTER JOIN pour réconcilier deux sources de données :
-- Réconciliation clients CRM vs système bancaireSELECTCOALESCE(crm.numero_client, sb.numero_client) as client,
crm.nom_complet,
sb.solde_total,
CASEWHEN crm.numero_client ISNULLTHEN'Client technique sans CRM'WHEN sb.numero_client ISNULLTHEN'Client CRM sans compte'ELSE'Client complet'ENDas statut_reconciliation
FROM crm_clients crm
FULLOUTERJOIN systeme_bancaire sb ON crm.numero_client = sb.numero_client
WHERE crm.date_creation >='2023-01-01'OR sb.date_ouverture >='2023-01-01';
Ahmed, analyste logistique chez Amazon
Ahmed optimise les livraisons en analysant les retards par transporteur et région :
-- Analyse des retards de livraisonSELECT
t.nom_transporteur,
z.nom_zone,
COUNT(l.id) as nb_livraisons,
AVG(DATEDIFF(l.date_livraison_reelle, l.date_livraison_prevue)) as retard_moyen_jours,
SUM(CASEWHEN l.date_livraison_reelle > l.date_livraison_prevue THEN1ELSE0END) as nb_livraisons_retard
FROM commandes c
INNERJOIN livraisons l ON c.id = l.commande_id
INNERJOIN transporteurs t ON l.transporteur_id = t.id
INNERJOIN zones_livraison z ON c.code_postal BETWEEN z.cp_min AND z.cp_max
WHERE l.date_livraison_reelle ISNOT NULLAND c.date_commande >= DATE_SUB(NOW(), INTERVAL3MONTH)
GROUPBY t.id, t.nom_transporteur, z.id, z.nom_zone
HAVING nb_livraisons >=10ORDERBY retard_moyen_jours DESC;
Validation et bonnes pratiques
1. Toujours vérifier les cardinalités
Avant d'écrire un JOIN, posez-vous ces questions :
Relation 1:1, 1:N ou N:N ?
Y a-t-il des valeurs NULL dans les clés de jointure ?
Y a-t-il des valeurs orphelines ?
-- Vérification des cardinalités avant jointureSELECT'employes'as table_name, COUNT(*) as total, COUNT(DISTINCT departement_id) as nb_dept_uniques
FROM employes
UNIONALLSELECT'departements', COUNT(*), COUNT(DISTINCT id)
FROM departements;
2. Utiliser EXPLAIN pour optimiser
-- Analyser le plan d'exécution
EXPLAIN ANALYZE
SELECT e.nom, d.nom_departement
FROM employes e
INNERJOIN departements d ON e.departement_id = d.id
WHERE e.date_embauche >'2024-01-01';
3. Documenter les jointures complexes
-- Jointure métier : associer les ventes aux commissions par niveau hiérarchiqueSELECT
v.nom_vendeur,
c.montant_commande,
-- Commission vendeur (taux 5%)
c.montant_commande *0.05as commission
FROM vendeurs v
INNERJOIN commandes c ON v.id = c.vendeur_id;
Tableau récapitulatif des JOINs
Type de JOIN
Lignes retournées
Cas d'usage
Fréquence d'utilisation
INNER JOIN
Seulement les correspondances
Données complètes, aucune valeur manquante
★★★★★
LEFT JOIN
Toutes les lignes de gauche
Lister les données + valeurs orphelines
★★★★★
RIGHT JOIN
Toutes les lignes de droite
Cas rare (inverser les tables)
★☆☆☆☆
FULL OUTER JOIN
Toutes les lignes des deux tables
Réconciliation complète
★★☆☆☆
CROSS JOIN
Produit cartésien
Générer des combinaisons
★★☆☆☆
SELF JOIN
Dépend du type (INNER/LEFT)
Hiérarchies, paires de données
★★★☆☆
Exercices corrigés
Exercice 1 : Anti-JOIN (LEFT JOIN + WHERE IS NULL)
Trouvez tous les produits qui n'ont jamais été commandés.
💡 Bon à savoir
Cet exercice teste votre compréhension du piège WHERE + LEFT JOIN. Il revient dans presque 80 % des entretiens selon nos données.
-- SolutionSELECT p.id, p.nom_produit
FROM produits p
LEFTJOIN lignes_commande lc ON p.id = lc.produit_id
WHERE lc.id ISNULL;
Exercice 2 : JOINs multiples avec GROUP BY
Calculez le nombre de commandes et le montant total par client, même pour ceux sans commande.
-- SolutionSELECT
c.id,
c.nom_client,
COUNT(co.id) as nb_commandes,
COALESCE(SUM(co.montant), 0) as montant_total
FROM clients c
LEFTJOIN commandes co ON c.id = co.client_id
GROUPBY c.id, c.nom_client
ORDERBY montant_total DESC;
Exercice 3 : SELF JOIN
Trouvez tous les couples d'employés du même département.
-- SolutionSELECT
e1.nom AS employe_1,
e2.nom AS employe_2,
d.nom_departement
FROM employes e1
INNERJOIN employes e2 ON e1.departement_id = e2.departement_id
INNERJOIN departements d ON e1.departement_id = d.id
WHERE e1.id < e2.id -- éviter les doublonsORDERBY d.nom_departement, employe_1;
Exercice 4 : FULL OUTER JOIN
Comparez les listes de clients CRM et du système de facturation.
-- Solution en PostgreSQL/SQL ServerSELECTCOALESCE(crm.id, facturation.id) as client_id,
crm.nom as nom_crm,
facturation.nom as nom_facturation,
CASEWHEN crm.id ISNULLTHEN'Seulement en facturation'WHEN facturation.id ISNULLTHEN'Seulement en CRM'ELSE'Présent dans les deux'ENDas statut
FROM clients_crm crm
FULLOUTERJOIN clients_facturation facturation
ON crm.id = facturation.id
ORDERBY client_id;
En MySQL, utiliser UNION à la place.
Exercice 5 : Jointure avec condition composée
Trouvez les employés affectés à un projet pendant une période donnée.
-- SolutionSELECT
e.nom,
p.nom_projet,
af.date_debut,
af.date_fin
FROM employes e
INNERJOIN affectations af ON e.id = af.employe_id
INNERJOIN projets p ON af.projet_id = p.id
WHERE af.date_debut <='2024-03-31'ANDCOALESCE(af.date_fin, '9999-12-31') >='2024-01-01'ORDERBY e.nom, af.date_debut;
Lien avec les autres concepts SQL
Les JOINs s'articulent avec d'autres concepts fondamentaux :
Quelle est la différence entre WHERE et ON dans un JOIN ?
ON s'exécute pendant la jointure et détermine quelles lignes sont associées. WHERE s'exécute après la jointure et filtre le résultat. Avec un LEFT JOIN, une condition en WHERE peut éliminer les lignes NULL (valeur ajoutées) et transformer silencieusement le LEFT JOIN en INNER JOIN.
Pourquoi ma LEFT JOIN retourne moins de lignes que la table de gauche ?
Probablement parce que vous avez une condition WHERE sur la table de droite. Déplacez cette condition dans le ON, ou vérifiez que vous ne joignez pas sur plusieurs tables (problème de cardinalité N:N non gérée).
Comment optimiser une requête avec 5 JOINs ?
Utilisez EXPLAIN/EXPLAIN ANALYZE pour voir le plan d'exécution. Vérifiez que les colonnes de jointure sont indexées. Reordonnez les JOINs pour filtrer au maximum dès les premières jointures. Envisagez une approche par CTE pour améliorer la lisibilité et la performance.
Peux-je joindre sur un calcul ? Ex: ON a.prix * 1.1 = b.prix
Oui, mais c'est très inefficace. L'optimiseur ne peut pas utiliser d'index sur un calcul. Privilégiez l'approche inverse : calculer dans SELECT et filtrer en WHERE.
Qu'est-ce qu'un LATERAL JOIN ?
(PostgreSQL) Un LATERAL JOIN permet à une sous-requête de droite d'accéder aux colonnes de gauche, comme une boucle. Utile pour des calculs ligne par ligne complexes. MySQL l'approche avec CROSS JOIN + subqueries.
Pourquoi dois-je utiliser COALESCE dans FULL OUTER JOIN ?
Parce que quand une ligne n'existe que d'un côté, ses colonnes de l'autre côté sont NULL. COALESCE(a.id, b.id) vous donne l'ID quelle que soit sa source.
Quel est le JOIN le plus performant ?
INNER JOIN est généralement le plus rapide (moins de lignes à traiter). LEFT JOIN peut être lent si la table de gauche est énorme. Toujours indexer les colonnes de jointure (surtout les clés étrangères).
Prêt à vous entraîner ?
50 exercices SQL interactifs avec éditeur en ligne, chronomètre et feedback IA.