Une sous-requête est une requête SELECT imbriquée à l'intérieur d'une autre requête. Elle permet de répondre à des questions en plusieurs étapes sans avoir à écrire du code applicatif intermédiaire. Voyons les principales formes.
A subquery is a SELECT query nested inside another query. It lets you answer multi-step questions without writing intermediate application code. Let's look at the main forms.
Sous-requête dans le WHERE
Subquery in the WHERE Clause
La forme la plus courante : filtrer selon le résultat d'une autre requête.
The most common form: filtering based on the result of another query.
SELECT nom
FROM clients
WHERE id IN (
SELECT client_id FROM commandes WHERE montant > 100
);
SELECT name
FROM customers
WHERE id IN (
SELECT customer_id FROM orders WHERE amount > 100
);
Ici, la sous-requête renvoie d'abord la liste des client_id ayant une commande de plus de 100, puis la requête externe filtre les clients correspondants.
Here, the subquery first returns the list of customer_id values with an order over 100, then the outer query filters the matching customers.
Sous-requête corrélée
Correlated Subquery
Une sous-requête corrélée référence une colonne de la requête externe : elle est donc réévaluée pour chaque ligne.
A correlated subquery references a column from the outer query, so it's re-evaluated for every row.
SELECT c.nom
FROM clients c
WHERE EXISTS (
SELECT 1 FROM commandes co
WHERE co.client_id = c.id AND co.montant > 100
);
SELECT c.name
FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.customer_id = c.id AND o.amount > 100
);
Ce style, combiné à EXISTS, est souvent plus performant qu'un IN sur de grandes tables car le moteur peut s'arrêter dès qu'une correspondance est trouvée.
This style, combined with EXISTS, is often more performant than IN on large tables because the engine can stop as soon as a match is found.
EXISTS à IN quand la sous-requête peut renvoyer beaucoup de lignes ou contenir des NULL — IN se comporte parfois de façon contre-intuitive avec les NULL.
Tip: prefer EXISTS over IN when the subquery might return many rows or contain NULL values — IN sometimes behaves counter-intuitively with NULL.
Sous-requête dans le FROM
Subquery in the FROM Clause
Une sous-requête peut aussi servir de table temporaire, souvent appelée table dérivée.
A subquery can also serve as a temporary table, often called a derived table.
SELECT ventes_par_client.nom, ventes_par_client.total
FROM (
SELECT c.nom, SUM(co.montant) AS total
FROM clients c
JOIN commandes co ON co.client_id = c.id
GROUP BY c.nom
) AS ventes_par_client
WHERE ventes_par_client.total > 200;
SELECT sales_by_customer.name, sales_by_customer.total
FROM (
SELECT c.name, SUM(o.amount) AS total
FROM customers c
JOIN orders o ON o.customer_id = c.id
GROUP BY c.name
) AS sales_by_customer
WHERE sales_by_customer.total > 200;
C'est utile quand on doit filtrer ou trier sur un résultat déjà agrégé, puisque WHERE ne peut pas directement utiliser un alias calculé avec SUM.
This is useful when you need to filter or sort on an already-aggregated result, since WHERE can't directly use an alias computed with SUM.
Sous-requête dans le SELECT
Subquery in the SELECT Clause
On peut aussi placer une sous-requête scalaire (qui renvoie une seule valeur) directement dans la liste de colonnes.
You can also place a scalar subquery (one that returns a single value) directly in the column list.
SELECT
c.nom,
(SELECT COUNT(*) FROM commandes co WHERE co.client_id = c.id) AS nb_commandes
FROM clients c;
SELECT
c.name,
(SELECT COUNT(*) FROM orders o WHERE o.customer_id = c.id) AS order_count
FROM customers c;
Attention : cette forme exécute la sous-requête une fois par ligne de la table externe. Pour de gros volumes, une jointure avec GROUP BY est en général plus performante.
Careful: this form executes the subquery once per row of the outer table. For large volumes, a join with GROUP BY is generally more performant.
Sous-requête vs jointure : que choisir ?
Subquery vs. Join: Which to Choose?
| Situation | Recommandation |
|---|---|
| Vérifier l'existence d'une correspondance | Sous-requête avec EXISTS |
| Récupérer des colonnes des deux tables | JOIN |
| Filtrer sur un résultat agrégé | Sous-requête dans le FROM, ou HAVING |
| Grandes tables, performance critique | Tester les deux avec EXPLAIN |
| Situation | Recommendation |
|---|---|
| Check whether a match exists | Subquery with EXISTS |
| Retrieve columns from both tables | JOIN |
| Filter on an aggregated result | Subquery in FROM, or HAVING |
| Large tables, performance-critical | Test both with EXPLAIN |
