MÉMO - Les sous-requêtes SQL
Trouver les clients dont le montant total commandé dépasse la moyenne, ou lister les produits jamais commandés : ce genre de question ne peut pas se résoudre avec un simple WHERE portant sur une valeur fixe, parce que la valeur de comparaison dépend elle-même d'un calcul sur la base.
C'est le rôle de la sous-requête (ou requête imbriquée) : une instruction SELECT complète, placée à l'intérieur d'une autre requête.
La question qui revient souvent : où placer une sous-requête, et avec quel opérateur la relier à la requête principale ?
Réponse rapide
| Question | Réponse |
| Où peut-on placer une sous-requête ? | le plus souvent dans le WHERE (ou le HAVING) de la requête principale, entre parenthèses |
| Que renvoie-t-elle à la requête principale ? | selon l'opérateur utilisé : une valeur unique (=, <, >...), une liste de valeurs (IN), ou juste une existence (EXISTS) |
| Doit-elle être exécutée en premier ? | conceptuellement oui : le SGBD évalue la sous-requête pour obtenir la valeur ou la liste dont la requête principale a besoin |
Les trois formes de sous-requête
| Opérateur | Utilisation | La sous-requête doit renvoyer |
| =, <, >, <=, >= | comparer une colonne à une valeur unique calculée | une seule valeur, une seule ligne |
| IN | vérifier qu'une valeur appartient à un ensemble | une liste de valeurs (une colonne, plusieurs lignes) |
| EXISTS / NOT EXISTS | vérifier qu'au moins une ligne correspondante existe (ou n'existe pas) | peu importe le contenu, seule l'existence d'au moins une ligne compte |
Exemple d'application
Tables CLIENT (codeclient, nomclient) et COMMANDE (numcommande, codeclient, montantht). On veut la liste des clients dont au moins une commande dépasse la moyenne générale des commandes.
|
SELECT nomclient |
|
FROM CLIENT |
|
WHERE codeclient IN ( |
|
SELECT codeclient |
|
FROM COMMANDE |
|
WHERE montantht > (SELECT AVG(montantht) FROM COMMANDE) |
|
); |
Cette requête imbrique même deux niveaux de sous-requête : la plus interne calcule la moyenne générale (une valeur unique, comparée avec >) ; la sous-requête intermédiaire renvoie la liste des codeclient correspondants (comparée avec IN) ; la requête principale affiche enfin le nom des clients concernés.
Autre cas fréquent : lister les clients qui n'ont jamais passé de commande, avec NOT EXISTS.
|
SELECT nomclient |
|
FROM CLIENT C |
|
WHERE NOT EXISTS ( |
|
SELECT 1 FROM COMMANDE CD WHERE CD.codeclient = C.codeclient |
|
); |
Erreurs fréquentes et bonnes pratiques
| Erreur | Bonne pratique |
| Utiliser = alors que la sous-requête peut renvoyer plusieurs lignes | dès qu'un doute existe sur le nombre de lignes renvoyées, utiliser IN plutôt que = (qui échoue si la sous-requête renvoie plus d'une valeur) |
| Oublier les parenthèses autour de la sous-requête | une sous-requête doit toujours être entre parenthèses, qu'elle suive =, IN ou EXISTS |
| Confondre sous-requête et jointure | une jointure combine des colonnes de deux tables sur la même ligne de résultat ; une sous-requête ne sert qu'à calculer une valeur ou une liste de comparaison — les deux ne sont pas interchangeables dans tous les cas |
| Répéter le même alias de table entre la requête principale et la sous-requête (sous-requête corrélée) | utiliser des alias distincts (ex. C pour la table externe, CD pour la table interne) afin que le SGBD sache à quelle occurrence de la table chaque colonne se réfère |
En résumé
| Point clé | Réponse |
| Sous-requête qui renvoie une seule valeur | comparaison directe avec =, <, >... |
| Sous-requête qui renvoie une liste de valeurs | utiliser IN |
| Sous-requête qui vérifie seulement une existence | utiliser EXISTS / NOT EXISTS |



