Dans le chapitre précédent, on a vu SELECT, INSERT, UPDATE : tes premières requêtes. Tu sais interroger une table. Maintenant, on en combine plusieurs.
🎯 Objectif : Maîtriser les jointures SQL (INNER, LEFT, RIGHT, FULL, CROSS JOIN) et les sous-requêtes pour croiser les données entre tables.
Pourquoi les jointures existent
En base relationnelle, les données sont réparties dans plusieurs tables pour éviter la redondance. Un serveur appartient à un datacenter, héberge des services, génère des alertes — chaque concept a sa table. Les jointures reconstituent le puzzle.
On travaille avec ce schéma DevOps :
-- servers(server_id, hostname, ip_address, environment, datacenter_id, status)
-- datacenters(datacenter_id, name, location, provider)
-- services(service_id, name, server_id, port, status)
-- alerts(alert_id, server_id, severity, message, created_at, resolved_at)
La colonne datacenter_id dans servers est une clé étrangère — elle pointe vers la clé primaire de datacenters. C’est cette relation qui rend la jointure possible. Sans clé étrangère, tu peux toujours joindre sur n’importe quelle colonne, mais la cohérence des données n’est plus garantie par la base.
INNER JOIN : les correspondances
L’INNER JOIN retourne uniquement les lignes qui ont une correspondance dans les deux tables. Pas de match = pas dans le résultat.
-- Serveurs avec leur datacenter
SELECT s.hostname, s.ip_address, s.environment,
d.name AS datacenter, d.location
FROM servers s
INNER JOIN datacenters d ON s.datacenter_id = d.datacenter_id;
💡 JOIN et INNER JOIN sont synonymes. Le mot INNER est optionnel, mais le garder rend le code plus explicite — surtout quand tu mélanges plusieurs types de jointures.
Jointures multi-tables
On peut chaîner les jointures pour croiser 3 tables ou plus :
-- Services avec leur serveur et datacenter
SELECT svc.name AS service, svc.port,
s.hostname, d.name AS datacenter
FROM services svc
JOIN servers s ON svc.server_id = s.server_id
JOIN datacenters d ON s.datacenter_id = d.datacenter_id
WHERE svc.status = 'running';
Chaque JOIN ajoute une table au résultat. L’ordre de lecture : on part des services, on rattache le serveur, puis le datacenter. C’est comme remonter une chaîne de relations. En pratique, tu chaîneras rarement plus de 4-5 jointures — au-delà, la requête devient difficile à maintenir et les performances peuvent se dégrader.
LEFT JOIN : tout garder à gauche
Le LEFT JOIN retourne toutes les lignes de la table de gauche, même sans correspondance à droite. Les colonnes manquantes prennent la valeur NULL.
-- Tous les serveurs, même ceux sans datacenter
SELECT s.hostname, s.ip_address,
d.name AS datacenter
FROM servers s
LEFT JOIN datacenters d ON s.datacenter_id = d.datacenter_id;
Un serveur legacy-01 sans datacenter_id apparaîtra avec NULL dans la colonne datacenter. Avec un INNER JOIN, il serait exclu du résultat.
Trouver les orphelins
Le pattern LEFT JOIN + WHERE ... IS NULL est un classique pour détecter les données sans correspondance :
🔥 Le pattern LEFT JOIN ... WHERE IS NULL est essentiel en audit d’infrastructure. Serveurs orphelins, services sans serveur, utilisateurs sans rôle — tu retrouveras cette technique partout. Exemple : SELECT s.hostname FROM servers s LEFT JOIN datacenters d ON s.datacenter_id = d.datacenter_id WHERE d.datacenter_id IS NULL — ça trouve les serveurs sans datacenter.
RIGHT JOIN et FULL OUTER JOIN
Le RIGHT JOIN fait l’inverse du LEFT : toutes les lignes de la table de droite. En pratique, on l’utilise rarement — on inverse l’ordre des tables et on fait un LEFT JOIN, c’est plus lisible.
Le FULL OUTER JOIN retourne toutes les lignes des deux tables, avec NULL des deux côtés quand il n’y a pas de correspondance :
SELECT s.hostname, d.name AS datacenter
FROM servers s
FULL OUTER JOIN datacenters d ON s.datacenter_id = d.datacenter_id;
⚠️ FULL OUTER JOIN n’existe pas dans MySQL. On le simule avec un UNION de LEFT JOIN et RIGHT JOIN. PostgreSQL le supporte nativement.
CROSS JOIN et auto-jointure
Le CROSS JOIN produit le produit cartésien — chaque ligne de A combinée avec chaque ligne de B. 5 × 3 = 15 résultats. Utile pour générer des combinaisons, rarement pour l’analyse.
L’auto-jointure (self join) connecte une table à elle-même. Classique pour les hiérarchies :
-- Employés avec le nom de leur manager
SELECT e.name AS employee, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;
Sous-requêtes : requêtes dans les requêtes
Une sous-requête est une requête imbriquée dans une autre. Elle peut apparaître dans le WHERE, le FROM ou le SELECT.
Dans le WHERE avec IN et EXISTS
-- IN : serveurs hébergeant un service critique
SELECT hostname, ip_address FROM servers
WHERE server_id IN (
SELECT server_id FROM services
WHERE name IN ('postgresql', 'redis', 'kafka')
);
-- EXISTS : serveurs avec au moins une alerte non résolue
SELECT s.hostname FROM servers s
WHERE EXISTS (
SELECT 1 FROM alerts a
WHERE a.server_id = s.server_id AND a.resolved_at IS NULL
);
-- NOT EXISTS : serveurs sans aucun service
SELECT hostname FROM servers s
WHERE NOT EXISTS (
SELECT 1 FROM services svc WHERE svc.server_id = s.server_id
);
💡 EXISTS est souvent plus performant que IN pour les sous-requêtes corrélées. Le moteur SQL peut s’arrêter dès qu’il trouve une correspondance, sans scanner toute la sous-table.
Les sous-requêtes peuvent aussi apparaître dans le FROM (tables dérivées) et le SELECT (sous-requêtes scalaires). Dans le FROM, n’oublie pas l’alias obligatoire en PostgreSQL : FROM (SELECT ...) AS alias.
Cas entreprise : audit d’infrastructure
Tu arrives dans une boîte et tu dois auditer l’infra. Les données sont dans PostgreSQL. Voici les requêtes qui donnent une vue d’ensemble en 5 minutes :
-- Vue globale : serveurs par datacenter et environnement
SELECT d.name AS datacenter, s.environment,
COUNT(*) AS nb_servers,
SUM(s.cpu_cores) AS total_cpus,
SUM(s.ram_gb) AS total_ram
FROM servers s
JOIN datacenters d ON s.datacenter_id = d.datacenter_id
GROUP BY d.name, s.environment
ORDER BY d.name, s.environment;
-- Services exposés sans serveur actif (risque !)
SELECT svc.name, svc.port, s.hostname, s.status
FROM services svc
JOIN servers s ON svc.server_id = s.server_id
WHERE svc.status = 'running' AND s.status != 'running';
-- Top 5 serveurs les plus alertés ce mois
SELECT s.hostname, COUNT(a.alert_id) AS alert_count
FROM servers s
JOIN alerts a ON s.server_id = a.server_id
WHERE a.created_at >= '2026-03-01'
GROUP BY s.hostname
ORDER BY alert_count DESC
LIMIT 5;
🎯 Ces trois requêtes te donnent : la répartition des ressources, les risques immédiats (services sur serveurs down), et les serveurs problématiques. C’est la base de tout audit infra.
Résumé
🔥 Ce qu’on a couvert : INNER JOIN pour les correspondances exactes, LEFT JOIN pour garder toutes les lignes d’un côté (et le pattern IS NULL pour les orphelins), FULL OUTER JOIN et CROSS JOIN pour les cas spécifiques, les sous-requêtes dans WHERE (IN, EXISTS), dans FROM (tables dérivées) et dans SELECT (scalaires).
Les jointures sont le cœur de SQL. Une base relationnelle sans jointures, c’est comme un tableur — utile mais limité. Avec les jointures, tu peux croiser n’importe quelles données en une seule requête. Et les sous-requêtes ajoutent un niveau de puissance supplémentaire pour les analyses complexes et la détection d’anomalies dans ton infrastructure.
💡 À retenir : commence toujours par un
INNER JOIN. Si tu as besoin de garder les lignes sans correspondance, passe enLEFT JOIN. Et le patternLEFT JOIN ... WHERE IS NULLpour trouver les orphelins — grave-le dans ta mémoire, tu l’utiliseras tous les jours.
Contenu réservé aux abonnés
Ce chapitre fait partie de la formation complète. Abonne-toi pour débloquer tous les contenus.
Débloquer pour 29 CHF/moisLe chapitre 1 de chaque formation est gratuit.
Série pas encore débloquée
Termine la série prérequise d'abord pour accéder à ce contenu.
Aller à la série prérequiseSérie : Apprendre SQL
3 / 6Sur cette page
Articles liés
Sous-requêtes et agrégations
Opérations ensemblistes (UNION, INTERSECT, EXCEPT), vues SQL, index et optimisation des performances. Le SQL avancé en pratique.
Pourquoi SQL ? Les bases de données expliquées
Découvre ce qu'est SQL, les bases de données relationnelles, les SGBD, les propriétés ACID, les types de données, et écris tes premières requêtes SELECT et WHERE.
SELECT, INSERT, UPDATE : tes premières requêtes
Maîtrise ORDER BY, LIMIT, les fonctions d'agrégation (COUNT, SUM, AVG), GROUP BY et HAVING. Avec des exemples pratiques DevOps.