SQL · Requêtes avancées

Guide pratique sur les sous-requêtes SQL (requêtes imbriquées)

Maîtrisez les sous-requêtes dans WHERE, FROM, SELECT, les sous-requêtes corrélées et leur utilisation avec INSERT, UPDATE, DELETE. Exemples concrets et bonnes pratiques.

Niveau : intermédiaire | Temps de lecture : 12 min | Mis à jour : avril 2026

1. Introduction aux sous-requêtes

Les sous-requêtes (ou requêtes imbriquées) en SQL sont des requêtes incluses dans une autre requête. Elles permettent de réaliser des opérations complexes en décomposant un problème en plusieurs étapes.

Définition

Une sous-requête est une requête SQL placée à l'intérieur d'une autre requête (SELECT, INSERT, UPDATE, DELETE). Elle peut être utilisée dans les clauses SELECT, FROM, WHERE, HAVING.

Types de sous-requêtes

  • Sous-requête dans WHERE : Filtrer les résultats en fonction d'une condition dynamique.
  • Sous-requête dans FROM : Créer une table temporaire (dérivée).
  • Sous-requête dans SELECT : Retourner une valeur calculée par ligne.
  • Sous-requête corrélée : Dépend de la requête externe (exécutée ligne par ligne).
85%
des requêtes complexes utilisent au moins une sous-requête
Analyse logs, 2025
3x
plus lisible qu'une requête monolithique
Stack Overflow Survey, 2026

Schéma des sous-requêtes SQL

 

2. Sous-requête dans la clause WHERE

Cas d'utilisation :

Filtrer les résultats en fonction d'une condition dynamique ou comparer une valeur avec un résultat calculé.

Exemple 1 : Trouver les clients ayant passé une commande

IN avec sous-requête
-- Tables : Clients(ClientID, Nom), Commandes(OrderID, ClientID, Date)

SELECT ClientID, Nom
FROM Clients
WHERE ClientID IN (SELECT DISTINCT ClientID FROM Commandes);

Exemple 2 : Trouver les produits dont le prix est supérieur à la moyenne

Comparaison avec une valeur scalaire
-- Table : Produits(ProduitID, Nom, Prix)

SELECT ProduitID, Nom, Prix
FROM Produits
WHERE Prix > (SELECT AVG(Prix) FROM Produits);

Opérateurs utilisables avec sous-requêtes WHERE

  • IN / NOT IN : valeur présente dans la liste retournée
  • EXISTS / NOT EXISTS : existence d'au moins une ligne
  • >, <, =, >=, <= : comparaison avec une valeur scalaire
  • ANY / SOME : comparaison avec au moins une valeur
  • ALL : comparaison avec toutes les valeurs
EXISTS vs IN
-- EXISTS (souvent plus performant pour les grandes tables)
SELECT * FROM Clients c
WHERE EXISTS (SELECT 1 FROM Commandes o WHERE o.ClientID = c.ClientID);

-- IN (plus lisible pour les petites listes)
SELECT * FROM Clients
WHERE ClientID IN (1, 2, 3, 4, 5);

3. Sous-requête dans la clause FROM

Cas d'utilisation :

Créer une table temporaire (dérivée) pour simplifier une requête complexe ou pré-agréger des données.

Exemple : Calculer le revenu total par client

Table dérivée avec GROUP BY
SELECT c.ClientID, c.Nom, COALESCE(TotalRevenu, 0) AS TotalRevenu
FROM Clients c
LEFT JOIN (
    SELECT ClientID, SUM(Montant) AS TotalRevenu
    FROM Commandes
    GROUP BY ClientID
) AS RevenuClients
ON c.ClientID = RevenuClients.ClientID;
Astuce : Les sous-requêtes dans FROM sont aussi appelées "tables dérivées". Elles sont indispensables quand vous devez agréger avant de joindre.

4. Sous-requête dans la clause SELECT

Cas d'utilisation :

Retourner une valeur calculée pour chaque ligne (sous-requête scalaire).

Exemple : Afficher le nombre de commandes par client

Sous-requête scalaire dans SELECT
SELECT c.ClientID, c.Nom, 
       (SELECT COUNT(*) 
        FROM Commandes o 
        WHERE o.ClientID = c.ClientID) AS NombreCommandes
FROM Clients c;
 Contrainte : Une sous-requête dans SELECT doit retourner une seule valeur (une ligne, une colonne). Si elle retourne plusieurs lignes, la requête échoue.

5. Sous-requêtes corrélées

Définition :

Une sous-requête corrélée dépend de la requête externe. Elle est exécutée une fois pour chaque ligne de la requête principale.

Exemple : Employés avec salaire > moyenne de leur département

Sous-requête corrélée
SELECT e.EmployéID, e.Nom, e.Salaire, e.DépartementID
FROM Employés e
WHERE e.Salaire > (
    SELECT AVG(Salaire)
    FROM Employés e2
    WHERE e2.DépartementID = e.DépartementID  -- Corrélation ici
);
Attention
Les sous-requêtes corrélées peuvent être lentes sur les grandes tables
Car exécutées ligne par ligne
Info
Alternative : fonction de fenêtrage (si SGBD supporte)
AVG() OVER(PARTITION BY DépartementID)

6. Sous-requêtes dans INSERT, UPDATE, DELETE

Exemple 1 : INSERT avec sous-requête

Insérer les nouveaux clients (sans doublon)
INSERT INTO Clients (ClientID, Nom)
SELECT ClientID, Nom
FROM NouveauxClients
WHERE ClientID NOT IN (SELECT ClientID FROM Clients);

Exemple 2 : UPDATE avec sous-requête corrélée

Augmenter les salaires inférieurs à la moyenne du département
UPDATE Employés e
SET Salaire = Salaire * 1.10
WHERE Salaire < (
    SELECT AVG(Salaire)
    FROM Employés e2
    WHERE e2.DépartementID = e.DépartementID
);

Exemple 3 : DELETE avec sous-requête

Supprimer les clients sans commande
DELETE FROM Clients
WHERE ClientID NOT IN (SELECT DISTINCT ClientID FROM Commandes);
 Attention : Sur MySQL, vous ne pouvez pas modifier une table et utiliser une sous-requête qui la référence dans la même requête (erreur 1093). Utilisez une table temporaire ou une jointure.

7. Requêtes complexes avec sous-requêtes

Exemple : Clients ayant passé plus de commandes que la moyenne

Double sous-requête (imbriquée)
SELECT c.ClientID, c.Nom, COUNT(o.OrderID) AS NombreCommandes
FROM Clients c
JOIN Commandes o ON c.ClientID = o.ClientID
GROUP BY c.ClientID, c.Nom
HAVING COUNT(o.OrderID) > (
    SELECT AVG(NombreCommandes)
    FROM (
        SELECT COUNT(OrderID) AS NombreCommandes
        FROM Commandes
        GROUP BY ClientID
    ) AS CommandesParClient
);

Exemple : Classement des clients par chiffre d'affaires

Sous-requête dans SELECT avec TOP/LIMIT
-- Top 5 clients (SQL Server)
SELECT TOP 5 ClientID, SUM(Montant) as CA
FROM Commandes
GROUP BY ClientID
ORDER BY CA DESC;

-- MySQL / PostgreSQL
SELECT ClientID, SUM(Montant) as CA
FROM Commandes
GROUP BY ClientID
ORDER BY CA DESC
LIMIT 5;

8. Sous-requêtes vs JOIN : quand utiliser quoi ?

Situation JOIN Sous-requête
Filtrer sur existence (IN/EXISTS) Possible mais moins intuitif✅ Plus lisible
Joindre après agrégation ✅ Table dérivée dans FROM ✅ Aussi possible
Ajouter une colonne calculée par ligne ❌ Nécessite GROUP BY ✅ Sous-requête scalaire dans SELECT
Performance sur grandes tables ✅ Généralement meilleur ⚠️ Corrélées peuvent être lentes
Règle simple :
  • JOIN : quand vous avez besoin de colonnes des deux tables.
  • Sous-requête : quand vous avez besoin d'un filtre conditionnel ou d'une valeur calculée.
  • EXISTS : souvent plus performant que IN pour les grandes tables.

9. Bonnes pratiques

1. Évitez les sous-requêtes inutiles

Préférez les JOIN quand vous avez besoin de colonnes des deux tables. Les sous-requêtes sont idéales pour les filtres et les calculs, moins pour les jointures.

2. Limitez la profondeur d'imbrication

Au-delà de 3-4 niveaux, la requête devient illisible. Utilisez des CTE (Common Table Expressions) pour clarifier.

3. Utilisez des alias explicites

Donnez des noms clairs aux sous-requêtes : AS CommandesParClient plutôt que AS t.

4. Testez les sous-requêtes séparément

Assurez-vous que chaque sous-requête fonctionne seule avant de l'intégrer. Cela facilite le débogage.

5. Préférez EXISTS à IN quand la sous-requête peut retourner NULL

NOT IN (SELECT ...) peut retourner UNKNOWN si la sous-requête contient des NULL. NOT EXISTS est plus sûr.

IN vs EXISTS avec NULL
--  DANGEREUX : si sous_requête contient NULL, NOT IN retourne UNKNOWN (aucune ligne)
DELETE FROM Clients WHERE ClientID NOT IN (SELECT ClientID FROM Commandes);

--  SÉCURISÉ : NOT EXISTS gère correctement les NULL
DELETE FROM Clients c
WHERE NOT EXISTS (SELECT 1 FROM Commandes o WHERE o.ClientID = c.ClientID);

10. Impact sur les performances

Bonnes pratiques de performance :
  • Les sous-requêtes non corrélées sont exécutées une fois → rapides.
  • Les sous-requêtes corrélées sont exécutées N fois → peuvent être lentes sur les grandes tables (N = nb de lignes de la table externe).
  • Utilisez EXPLAIN pour analyser le plan d'exécution.
  • Sur les très gros volumes, transformez les sous-requêtes corrélées en JOIN ou CTE.

11. FAQ — Sous-requêtes SQL

Quelle est la différence entre IN et EXISTS ?

IN compare une valeur à une liste (souvent une sous-requête). EXISTS teste l'existence d'au moins une ligne. EXISTS est souvent plus performant car il s'arrête dès qu'une ligne est trouvée. De plus, NOT EXISTS gère correctement les NULL, contrairement à NOT IN.

Une sous-requête peut-elle retourner plusieurs colonnes ?

Oui, mais uniquement dans certaines clauses. Dans FROM, une sous-requête peut retourner plusieurs colonnes. Dans WHERE avec IN, elle ne peut retourner qu'une colonne. Dans SELECT, elle doit retourner une seule valeur (scalaire).

Comment transformer une sous-requête en CTE ?

Les CTE (Common Table Expressions) rendent les requêtes plus lisibles :
WITH CommandesParClient AS (SELECT ClientID, COUNT(*) as Nb FROM Commandes GROUP BY ClientID)
SELECT * FROM Clients c JOIN CommandesParClient cp ON c.ClientID = cp.ClientID;

Les sous-requêtes sont-elles supportées dans tous les SGBD ?

Oui, les sous-requêtes sont standard SQL et supportées par tous les SGBD modernes (MySQL, PostgreSQL, SQL Server, Oracle, SQLite). Seules les fonctions de fenêtrage (qui remplacent parfois les sous-requêtes corrélées) ne sont pas disponibles partout.

Comment déboguer une sous-requête complexe ?

Exécutez la sous-requête seule pour vérifier son résultat. Utilisez des alias temporaires. Commentez les parties pour isoler l'erreur. Les CTE permettent de tester chaque bloc indépendamment.

Quand utiliser ALL et ANY ?

ALL : condition vraie pour toutes les valeurs (ex: Prix > ALL (SELECT Prix FROM Produits WHERE Categorie = 'Luxe')). ANY (ou SOME) : condition vraie pour au moins une valeur. Ces opérateurs sont moins courants mais utiles pour des comparaisons avancées.

Conclusion

Les sous-requêtes sont un outil puissant pour décomposer des problèmes complexes en étapes simples. Elles peuvent être utilisées dans WHERE, FROM, SELECT, HAVING et dans les opérations INSERT, UPDATE, DELETE.

À retenir

  • Les sous-requêtes non corrélées sont exécutées une seule fois.
  • Les sous-requêtes corrélées sont exécutées ligne par ligne (attention aux performances).
  • EXISTS est souvent plus performant que IN.
  • Préférez les CTE pour les requêtes très imbriquées.
  • Testez chaque sous-requête séparément avant intégration.
  • Attention aux NOT IN avec des NULL (préférez NOT EXISTS).
Pour aller plus loin : Découvrez notre tutoriel sur les fonctions de fenêtrage SQL pour des analyses encore plus avancées.
Faites parler vos données
Apprenez les méthodes et les outils pour extraire de la valeur stratégique : Data Science : Le guide complet des méthodes et outils.
 

Recevez la veille IA & Data qui compte vraiment

 

    Analyses claires, outils concrets et tendances IA sans bruit.     Rejoignez les lecteurs de IANA Data.