SQL self join : joindre une table avec elle-même
Parfois, la relation est à l'intérieur d'une même table. Dans la table employes, la colonne manager_id contient l'identifiant… d'un autre employé. Pour afficher « Léa travaille sous la responsabilité de Hugo », il faut joindre la table employes avec elle-même : c'est une auto-jointure.
Syntaxe
SELECT e.nom, m.nom AS manager
FROM employes e
LEFT JOIN employes m ON m.id = e.manager_id;Comment ça marche
Une auto-jointure n'a pas de mot-clé spécial : c'est un JOIN classique où la même table apparaît deux fois. Pour les distinguer, les alias sont obligatoires : ici e représente l'employé et m son manager.
On utilise souvent un LEFT JOIN, pour garder les lignes qui n'ont pas de « parent » (le PDG n'a pas de manager).
Les auto-jointures servent aussi à comparer des lignes entre elles : les employés qui gagnent plus que leur manager, les produits de même catégorie, les clients d'une même ville…
Schéma
| id | nom | manager_id |
|---|---|---|
| 1 | Durand | NULL |
| 2 | Martin | 1 |
| 3 | Roux | 2 |
| employé | manager |
|---|---|
| Durand | NULL |
| Martin | Durand |
| Roux | Martin |
Schéma simplifié pour illustrer le principe. Les exemples ci-dessous utilisent la vraie base d'exercices de SQL Quest (une boutique en ligne fictive : voir le schéma complet).
Exemples avec leurs résultats
1. Chaque employé et son manager
Le PDG apparaît avec un manager NULL grâce au LEFT JOIN.
SELECT e.prenom || ' ' || e.nom AS employe, e.poste,
m.prenom || ' ' || m.nom AS manager
FROM employes e
LEFT JOIN employes m ON m.id = e.manager_id
LIMIT 8; Essayer dans le bac à sable| employe | poste | manager |
|---|---|---|
| Chloé Dubois | PDG | NULL |
| Jade Lefebvre | Directeur commercial | Chloé Dubois |
| Nathan Roux | Directrice technique | Chloé Dubois |
| Samir Simon | Responsable RH | Chloé Dubois |
| Alice Simon | Commercial | Jade Lefebvre |
| Nathan Martin | Commercial | Jade Lefebvre |
| Lucas Moreau | Commercial | Jade Lefebvre |
| Emma Lambert | Commercial | Jade Lefebvre |
8 lignes au total
2. Compter les subordonnés
Combien de personnes chaque manager encadre-t-il directement ?
SELECT m.prenom, m.nom, m.poste, COUNT(e.id) AS equipe
FROM employes m
JOIN employes e ON e.manager_id = m.id
GROUP BY m.id
ORDER BY equipe DESC; Essayer dans le bac à sable| prenom | nom | poste | equipe |
|---|---|---|---|
| Jade | Lefebvre | Directeur commercial | 12 |
| Samir | Simon | Responsable RH | 5 |
| Nathan | Roux | Directrice technique | 4 |
| Chloé | Dubois | PDG | 3 |
4 lignes au total
3. Comparer deux lignes
Les employés qui gagnent plus que la moitié du salaire de leur manager.
SELECT e.nom, e.salaire, m.nom AS manager, m.salaire AS salaire_manager
FROM employes e
JOIN employes m ON m.id = e.manager_id
WHERE e.salaire > m.salaire / 2
LIMIT 8; Essayer dans le bac à sable| nom | salaire | manager | salaire_manager |
|---|---|---|---|
| Lefebvre | 6 200 | Dubois | 9 500 |
| Roux | 6 800 | Dubois | 9 500 |
| Simon | 4 800 | Dubois | 9 500 |
| Simon | 4 800 | Lefebvre | 6 200 |
| Martin | 3 400 | Lefebvre | 6 200 |
| Moreau | 4 600 | Lefebvre | 6 200 |
| Lambert | 4 200 | Lefebvre | 6 200 |
| Lefebvre | 3 800 | Lefebvre | 6 200 |
8 lignes au total
Les erreurs fréquentes
Oublier les alias
Sans alias, SQL ne peut pas savoir à quelle « copie » de la table chaque colonne appartient.
SELECT nom, nom FROM employes JOIN employes ON id = manager_id;SELECT e.nom, m.nom FROM employes e JOIN employes m ON m.id = e.manager_id;Inverser la condition
e.id = m.manager_id donne les subordonnés au lieu des managers. Relisez la condition : l'id du manager doit être égal au manager_id de l'employé.
SELECT e.nom, m.nom AS manager FROM employes e JOIN employes m ON e.id = m.manager_id;SELECT e.nom, m.nom AS manager FROM employes e JOIN employes m ON m.id = e.manager_id;Perdre le sommet de la hiérarchie
Avec un INNER JOIN, l'employé sans manager disparaît. Utilisez LEFT JOIN pour le garder.
SELECT e.nom, m.nom FROM employes e JOIN employes m ON m.id = e.manager_id;SELECT e.nom, m.nom FROM employes e LEFT JOIN employes m ON m.id = e.manager_id;Exercices
Essayez d'écrire la requête vous-même avant d'ouvrir la solution.
Défi 1. Affichez les employés (prénom, nom) dont le manager est le Directeur commercial.
Voir une solution
SELECT e.prenom, e.nom FROM employes e JOIN employes m ON m.id = e.manager_id WHERE m.poste = 'Directeur commercial';| prenom | nom |
|---|---|
| Alice | Simon |
| Nathan | Martin |
| Lucas | Moreau |
| Emma | Lambert |
| Alice | Lefebvre |
| Inès | Mercier |
| Louis | Bernard |
| Louis | Garcia |
12 lignes au total · 8 affichées
Essayer dans le bac à sableDéfi 2. Affichez chaque manager et le salaire moyen de son équipe.
Voir une solution
SELECT m.nom, ROUND(AVG(e.salaire)) AS salaire_moyen_equipe FROM employes m JOIN employes e ON e.manager_id = m.id GROUP BY m.id;| nom | salaire_moyen_equipe |
|---|---|
| Dubois | 5 933 |
| Lefebvre | 4 417 |
| Roux | 4 250 |
| Simon | 4 120 |
4 lignes au total
Essayer dans le bac à sableLes exercices interactifs sont corrigés automatiquement, avec un prof qui explique vos erreurs. Une leçon résumée reste affichée à côté de l'éditeur.
Questions fréquentes
Existe-t-il un mot-clé SELF JOIN ?
Non. Une auto-jointure s'écrit avec un JOIN ordinaire où la même table apparaît deux fois, avec deux alias différents.
Comment afficher toute la hiérarchie sur plusieurs niveaux ?
Avec une CTE récursive (WITH RECURSIVE), qui répète l'auto-jointure niveau par niveau.
Une auto-jointure est-elle lente ?
Pas plus qu'une jointure entre deux tables différentes. Un index sur la colonne de liaison (ici manager_id) l'accélère sur les grosses tables.