Imbriquez une requête dans une autre pour comparer à un agrégat, filtrer sur un ensemble ou tester une existence.
Ouvrir cette leçon dans KodokonUne 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.
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);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.
SELECT id, customer_id, amount
FROM orders
WHERE amount > (
SELECT AVG(amount) FROM orders
);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.
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
);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.
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;