🧱 Module 1 – Les JOINS en SQL#
Objectifs du module#
- Écrire tous les types de
JOIN
- Savoir quand utiliser
INNER
,LEFT
,RIGHT
,FULL
,CROSS
,SELF
- Identifier et corriger les pièges classiques (doublons, nulls, cardinalité)
- Résoudre des cas concrets (clients-commandes, utilisateurs-transactions, etc.)
🗂️ Fiche mémo rapide#
Type de JOIN | Fonction | Inclut les lignes de… | Syntaxe |
---|---|---|---|
INNER JOIN | Intersections | correspondance dans les deux tables | ... FROM A JOIN B ON A.id = B.id |
LEFT JOIN | Priorité à la gauche | toutes lignes de A + celles de B qui matchent | ... FROM A LEFT JOIN B ON A.id = B.id |
RIGHT JOIN | Priorité à la droite | toutes lignes de B + celles de A qui matchent | ... FROM A RIGHT JOIN B ON A.id = B.id |
FULL OUTER JOIN | Union + nulls | toutes les lignes de A et B | ... FROM A FULL JOIN B ON A.id = B.id |
CROSS JOIN | Produit cartésien | toutes combinaisons possibles | ... FROM A CROSS JOIN B |
SELF JOIN | Joindre une table avec elle-même | utile pour hiérarchie / comparaison | FROM A a1 JOIN A a2 ON a1.manager_id = a2.id |
💾 Dataset d’exemple (à créer dans DuckDB ou SQLite)#
-- Clients
CREATE TABLE clients (
client_id INTEGER,
nom TEXT
);
INSERT INTO clients VALUES
(1, 'Alice'),
(2, 'Bob'),
(3, 'Charlie');
-- Commandes
CREATE TABLE commandes (
commande_id INTEGER,
client_id INTEGER,
produit TEXT
);
INSERT INTO commandes VALUES
(101, 1, 'Chaise'),
(102, 1, 'Table'),
(103, 2, 'Canapé');
📘 Exemples commentés#
✅ INNER JOIN (seulement ceux qui ont commandé)#
SELECT c.nom, cmd.produit
FROM clients c
INNER JOIN commandes cmd ON c.client_id = cmd.client_id;
✅ LEFT JOIN (tous les clients, même sans commandes)#
SELECT c.nom, cmd.produit
FROM clients c
LEFT JOIN commandes cmd ON c.client_id = cmd.client_id;
✅ RIGHT JOIN (toutes les commandes, même sans client connu)#
(non supporté par SQLite, supporté par PostgreSQL et DuckDB)
SELECT c.nom, cmd.produit
FROM clients c
RIGHT JOIN commandes cmd ON c.client_id = cmd.client_id;
✅ FULL OUTER JOIN (tous les clients et commandes, même sans correspondance)#
SELECT c.nom, cmd.produit
FROM clients c
FULL OUTER JOIN commandes cmd ON c.client_id = cmd.client_id;
✅ CROSS JOIN (tous les couples clients-produits)#
SELECT c.nom, cmd.produit
FROM clients c
CROSS JOIN commandes cmd;
✅ SELF JOIN (cas d’un organigramme)#
CREATE TABLE employes (
emp_id INT,
nom TEXT,
manager_id INT
);
INSERT INTO employes VALUES
(1, 'Alice', NULL),
(2, 'Bob', 1),
(3, 'Charlie', 1),
(4, 'Dave', 2);
-- Lister chaque employé avec son manager
SELECT e1.nom AS employe, e2.nom AS manager
FROM employes e1
LEFT JOIN employes e2 ON e1.manager_id = e2.emp_id;
⚠️ Pièges classiques#
- ⚠️ Oublier la condition
ON
avecINNER JOIN
→ produit cartésien non désiré. - ⚠️
NULL
: unJOIN
surNULL = NULL
ne renvoie rien → utiliserIS NULL
parfois. - ⚠️
LEFT JOIN
: attention à ne pas appliquer des conditionsWHERE
sur la table de droite, sinon tu “annules” le LEFT JOIN.
-- Mauvais (filtre casse le LEFT JOIN)
SELECT * FROM clients c
LEFT JOIN commandes cmd ON c.client_id = cmd.client_id
WHERE cmd.produit = 'Chaise'; -- ← attention ici
-- Correct
SELECT * FROM clients c
LEFT JOIN commandes cmd ON c.client_id = cmd.client_id
WHERE cmd.produit = 'Chaise' OR cmd.produit IS NULL;
🏋️♂️ Exercices (à faire dans DuckDB, SQLite ou PostgreSQL)#
Exo 1#
Liste les clients qui ont commandé au moins un produit.
Exo 2#
Liste tous les clients, même ceux sans commande, avec le nom du produit (ou NULL).
Exo 3#
Combien de produits a commandé chaque client (y compris ceux avec 0) ?
Exo 4#
Liste tous les couples d’employés/manager.
Exo 5#
Effectue un CROSS JOIN
et affiche les 5 premières lignes.
🧪 Pour aller plus loin (ressources gratuites)#
- 📘 Mode Analytics – Visual SQL Joins
- 🧪 SQLZoo – Joins
- 🧠 LeetCode SQL – Niveau facile à moyen
- 🧠 StrataScratch – Requêtes réelles avec solution
🧰 Bonus : setup rapide pour tester (Python + DuckDB)#
import duckdb
import pandas as pd
duckdb.sql("""
CREATE TABLE clients AS SELECT * FROM (
VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie')
) AS t(client_id, nom);
CREATE TABLE commandes AS SELECT * FROM (
VALUES (101, 1, 'Chaise'), (102, 1, 'Table'), (103, 2, 'Canapé')
) AS t(commande_id, client_id, produit);
""")
# Exemple de JOIN
df = duckdb.sql("""
SELECT c.nom, cmd.produit
FROM clients c
LEFT JOIN commandes cmd ON c.client_id = cmd.client_id
""").df()
print(df)