Anida una consulta dentro de otra para comparar con un agregado, filtrar por un conjunto o comprobar la existencia.
Abrir esta lección en KodokonUna subconsulta es una consulta colocada entre paréntesis dentro de otra. En una sola instrucción responde preguntas como "los pedidos por encima de la media" o "los clientes con al menos un pedido". Ejecuta este script en sqliteonline.com o sqlite3 antes de empezar.
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);Colocada en WHERE, una subconsulta escalar debe devolver un único valor: una fila, una columna. El motor la calcula primero y luego la usa como cualquier otra constante. No puedes hacer esto con un simple WHERE amount > AVG(amount), que está prohibido en SQL.
SELECT id, customer_id, amount
FROM orders
WHERE amount > (
SELECT AVG(amount) FROM orders
);IN compara una columna con el conjunto de valores que devuelve la subconsulta. EXISTS comprueba si la subconsulta correlacionada (hace referencia a c.id, una columna de la consulta externa) devuelve al menos una fila: el motor se detiene en cuanto encuentra la primera coincidencia.
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
);En FROM, una subconsulta se comporta como una tabla temporal, llamada tabla derivada, y debe recibir un alias. Es la herramienta clásica para agregar en dos pasos: primero un total por cliente, luego la media de esos totales.
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;