Tu sais déjà comment joindre des tables avec JOIN. Mais dans la vraie vie, un simple match sur les clés ne suffit pas toujours. Souvent, il faut joindre les données seulement si elles remplissent un critère en plus — genre, seulement les lignes actives, ou juste les données de l'année en cours, ou uniquement les commandes terminées.
Et c'est là que l'extension de la clause ON avec AND entre en jeu.
Les conditions supplémentaires dans JOIN ... ON te permettent de contrôler précisément quelles lignes participent à la jointure, avant même que SQL commence à construire le résultat. Ça rend la requête :
- Plus rapide (moins de lignes passent par le
JOIN), - Plus précise (le filtrage se fait au moment de la jointure),
- Plus prévisible avec un
LEFT JOIN(contrairement au filtrage dansWHERE).
Exemple : Uniquement les inscriptions actives aux cours
Imaginons que la table enrollments contient le statut de participation de l'étudiant : active, dropped, pending.
Table students :
| id | nom |
|---|---|
| 1 | Otto Song |
| 2 | Maria Chi |
| 3 | Alex Lin |
Table enrollments mise à jour :
| student_id | course_id | statut |
|---|---|---|
| 1 | 101 | active |
| 1 | 103 | active |
| 2 | 102 | dropped |
| 3 | 101 | active |
Table courses :
| id | nom |
|---|---|
| 101 | Mathématiques |
| 102 | Physique |
| 103 | Informatique |
Maintenant, on veut récupérer seulement les étudiants qui ont des cours actifs :
SELECT
students.name AS student_name,
courses.name AS course_name
FROM students
INNER JOIN enrollments
ON students.id = enrollments.student_id
AND enrollments.status = 'active'
INNER JOIN courses
ON enrollments.course_id = courses.id;
Résultat :
| student_name | course_name |
|---|---|
| Otto Song | Mathématiques |
| Otto Song | Informatique |
| Alex Lin | Mathématiques |
Ici, on a ajouté AND enrollments.status = 'active' dans le ON, pour que la jointure se fasse uniquement sur les lignes actives, et pas en filtrant après la jointure.
Pourquoi pas WHERE ?
On aurait pu écrire comme ça :
...
WHERE enrollments.status = 'active'
Mais ça ne se comporte pas pareil avec un LEFT JOIN. Le filtrage dans WHERE enlève les lignes où il n'y a pas de match (NULL), et du coup transforme ton LEFT JOIN en INNER JOIN.
Alors que la condition AND enrollments.status = 'active' dans le ON limite direct les lignes à joindre — ça contrôle quelles lignes vont dans la jointure, pas juste le résultat final.
Cette approche est super importante si tu veux garder les lignes d'une table même si y'a rien en face dans l'autre table (ce qui arrive souvent dans les rapports et l'analytics).
Encore des exemples avec ON ... AND ...
Table students :
| id | nom |
|---|---|
| 1 | Otto Song |
| 2 | Maria Chi |
| 3 | Alex Lin |
Table enrollments :
| student_id | course_id | statut | enrolled_at |
|---|---|---|---|
| 1 | 101 | active | 2025-02-01 |
| 1 | 103 | active | 2025-03-05 |
| 2 | 102 | dropped | 2024-05-15 |
| 3 | 101 | active | 2025-03-12 |
Table courses :
| id | nom |
|---|---|
| 101 | Math |
| 102 | Physique |
| 103 | CS |
Exemple : uniquement les cours de l'année en cours
SELECT
students.name,
courses.name,
enrollments.enrolled_at
FROM students
JOIN enrollments
ON students.id = enrollments.student_id
AND EXTRACT(YEAR FROM enrollments.enrolled_at) = EXTRACT(YEAR FROM CURRENT_DATE)
JOIN courses
ON enrollments.course_id = courses.id;
Ici, on ne joint que les lignes qui concernent l'année en cours.
| nom | nom | enrolled_at |
|---|---|---|
| Otto Song | Math | 2025-02-01 |
| Otto Song | CS | 2025-03-05 |
| Alex Lin | Math | 2025-03-12 |
Exemple : exclusion par valeur
JOIN enrollments
ON students.id = enrollments.student_id
AND enrollments.status != 'dropped'
On exclut les étudiants qui ont abandonné au moment de la jointure, pas après.
| nom | nom |
|---|---|
| Otto Song | Math |
| Otto Song | CS |
| Alex Lin | Math |
Quand la condition est dans le ON, PostgreSQL peut optimiser le plan de jointure et traiter moins de lignes. C'est super important sur de gros volumes de données. Le filtrage interne est plus efficace que de "jeter" après le JOIN.
JOIN ON — c'est pas que pour les clés
Beaucoup pensent que ON c'est juste id = id. En vrai, tu peux mettre dedans :
- Opérateurs logiques :
AND,OR,NOT - Comparaisons :
>,<,<>,BETWEEN,IN - Expressions :
EXTRACT,DATE_TRUNC,COALESCE,NULLIF
On combine tout ensemble
Table students :
| id | nom |
|---|---|
| 1 | Otto Song |
| 2 | Maria Chi |
| 3 | Alex Lin |
Table faculties :
| id | nom | |
|---|---|---|
| 10 | Ingénierie | |
| 20 | Sciences naturelles | |
| 30 | ← sans nom (NULL) |
Table courses :
| id | nom | enseignant | faculty_id |
|---|---|---|---|
| 101 | Math | Liam Park | 10 |
| 102 | Physique | Chloe Zhang | 20 |
| 103 | CS | Noah Kim | 10 |
| 104 | EPS | Ava Chen | 30 |
Table enrollments :
| student_id | course_id | statut |
|---|---|---|
| 1 | 101 | active |
| 1 | 103 | active |
| 2 | 102 | dropped |
| 3 | 101 | active |
| 3 | 104 | active |
SELECT
s.name AS student_name,
c.name AS course_name,
f.name AS faculty_name
FROM students s
JOIN enrollments e
ON s.id = e.student_id
AND e.status = 'active'
JOIN courses c
ON e.course_id = c.id
AND c.name != 'EPS'
JOIN faculties f
ON c.faculty_id = f.id
AND f.name IS NOT NULL;
Ici, on filtre en même temps sur :
- Les lignes actives,
- Les cours sauf "EPS",
- Les facultés qui ont un nom.
Résultat de la requête :
| student_name | course_name | faculty_name |
|---|---|---|
| Otto Song | Math | Ingénierie |
| Otto Song | CS | Ingénierie |
| Alex Lin | Math | Ingénierie |
J'espère que t'as kiffé cette leçon. Tu vas utiliser super souvent plusieurs JOIN avec des filtres dans tes requêtes. Presque tout le temps :)
GO TO FULL VERSION