Kodokon kodokon.com

Sous-requêtes : WHERE, FROM, IN et EXISTS

Imbriquez une requête dans une autre pour comparer à un agrégat, filtrer sur un ensemble ou tester une existence.

9 min · 3 questions

Ouvrir cette leçon dans Kodokon

Une sous-requête est une requête placée entre parenthèses à l'intérieur d'une autre. Elle répond en une seule instruction à des questions comme « les commandes au-dessus de la moyenne » ou « les clients ayant au moins une commande ». Rejouez ce script dans sqliteonline.com ou sqlite3 avant de commencer.

SQL
CREATE TABLE customers (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL
);

CREATE TABLE orders (
  id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  amount REAL NOT NULL
);

INSERT INTO customers (id, name) VALUES
  (1, 'Alice'), (2, 'Karim'),
  (3, 'Mina'), (4, 'Paulo');

INSERT INTO orders (id, customer_id, amount)
VALUES
  (1, 1, 49.90), (2, 1, 15.00),
  (3, 2, 120.50), (4, 2, 80.00),
  (5, 3, 9.90), (6, 1, 200.00);
Jeu de données : quatre clients, six commandes.

Placée dans WHERE, une sous-requête scalaire doit renvoyer une seule valeur : une ligne, une colonne. Le moteur la calcule d'abord, puis l'utilise comme n'importe quelle constante. Impossible de faire cela avec un simple WHERE amount > AVG(amount), interdit en SQL.

SQL
SELECT id, customer_id, amount
FROM orders
WHERE amount > (
  SELECT AVG(amount) FROM orders
);
Les commandes au-dessus du panier moyen (79.22).

IN compare une colonne à l'ensemble de valeurs renvoyé par la sous-requête. EXISTS teste si la sous-requête corrélée (elle référence c.id, une colonne de la requête externe) renvoie au moins une ligne : le moteur s'arrête dès la première correspondance trouvée.

SQL
SELECT name FROM customers
WHERE id IN (
  SELECT customer_id FROM orders
  WHERE amount > 100
);

SELECT c.name FROM customers AS c
WHERE EXISTS (
  SELECT 1 FROM orders AS o
  WHERE o.customer_id = c.id
);
IN : les gros acheteurs. EXISTS : les clients actifs.

Dans FROM, une sous-requête se comporte comme une table temporaire, dite table dérivée, et doit recevoir un alias. C'est l'outil classique pour agréger en deux étapes : d'abord un total par client, puis la moyenne de ces totaux.

SQL
SELECT ROUND(AVG(t.total), 2) AS avg_basket
FROM (
  SELECT customer_id, SUM(amount) AS total
  FROM orders
  GROUP BY customer_id
) AS t;
Panier total moyen par client actif : 158.43.

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Combien de valeurs une sous-requête utilisée dans amount > (...) doit-elle renvoyer ?
    • Une seule
    • Une par ligne de la table externe
    • Autant qu'elle veut
  2. Quel est l'avantage principal d'EXISTS par rapport à IN ?
    • Il peut renvoyer plusieurs colonnes
    • Il s'arrête à la première ligne trouvée, sans matérialiser tout l'ensemble
    • Il fonctionne sans sous-requête
  3. Que doit obligatoirement porter une sous-requête placée dans FROM pour être portable partout ?
    • Un alias, comme AS t
    • Une clause ORDER BY
    • Un point-virgule interne