Subconsultas
En resumen: Una subconsulta es un SELECT dentro de otra consulta que devuelve un valor o una lista para WHERE y se usa con IN, EXISTS o NOT EXISTS.
Problema
Por encima del promedio
La gerencia quiere ver los productos que cuestan más que el precio promedio de la tienda. Ya conoces dos consultas: una encuentra el precio promedio y la otra busca productos por encima de un número dado.
Podrías ejecutar la primera, copiar el número y ejecutar la segunda. Pero mañana los precios serán otros, y el número copiado estará desactualizado.
La idea
Subconsulta
Primero, el precio promedio:
Ahora la misma consulta, entre paréntesis, en lugar del número:
Una consulta entre paréntesis dentro de otra consulta se llama subconsulta (subquery). La base de datos la ejecuta primero, obtiene 7,036 y luego revisa cada producto con price > 7.036. Salen ocho productos.
Esta subconsulta devuelve un número, así que va donde iría un número.
Más precisamente, para curiosos
Si una subconsulta dentro de una comparación devuelve varias filas, SQLite toma en silencio la primera. La categoría 8 («Cocina») tiene tres productos, pero la consulta compara con uno solo:
No se promete cuál fila es «la primera». PostgreSQL y SQL Server dan un error en este caso: la subconsulta devolvió más de una fila. Si una subconsulta puede devolver varias filas, usa IN.
Pruébalo
Más caro que el kashkaval
Muestra el nombre y el precio de los productos que cuestan más que el queso kashkaval. No escribas su precio a mano: obtenlo con una subconsulta.
Solución
SELECT name, price FROM products
WHERE price > (SELECT price FROM products WHERE name = 'Queso kashkaval');WHERE price > (SELECT price FROM products WHERE name = 'Queso kashkaval'). El queso cuesta 9,50 € y hay 6 productos más caros, desde la tabla de cortar (11,40 €) hasta el juego de cuchillos (39 €).
La idea
IN con una lista que sale de una consulta
Ya conoces IN con una lista escrita a mano: city IN ('Varna', 'Burgas'). La lista también puede venir de una subconsulta.
¿Qué clientes hicieron pedidos en octubre de 2026? Sus números están en orders y sus nombres en customers:
La subconsulta devuelve los números de los clientes con pedidos desde el 1 de octubre. La consulta exterior muestra los clientes cuyo id está en esa lista.
Las subconsultas se pueden anidar unas dentro de otras. Cada paso es una consulta aparte que puedes ejecutar y comprobar por sí sola.
Pruébalo
Quién compra café
El proveedor de café lanza un sabor nuevo y quiere escribir a las personas que ya compraron «Café en grano». Muestra sus nombres. El campo empieza con el primer paso: el número del producto.
Solución
SELECT name FROM customers
WHERE id IN (
SELECT customer_id FROM orders
WHERE id IN (
SELECT order_id FROM order_items
WHERE product_id = (SELECT id FROM products WHERE name = 'Café en grano')
)
);Tres pasos de dentro hacia fuera: el número del producto (17), los pedidos con una línea para él (order_items) y los clientes de esos pedidos (orders). Salen tres personas: Maria, Viktoria y Simona. Un JOIN también sirve: se compara el resultado, no el método.
La idea
EXISTS
A veces no te importa qué devuelve la subconsulta, sino solo si devuelve algo. ¿Qué clientes todavía no tienen pedidos?
EXISTS (…) es verdadero si la subconsulta devuelve al menos una fila. NOT EXISTS es lo contrario. Lo que va después de SELECT en la subconsulta no importa, por eso es SELECT 1.
Aquí la subconsulta mira la fila exterior: o.customer_id = c.id, donde c es el cliente que la consulta exterior está revisando en ese momento. Es una idea nueva, y la próxima lección la mira de cerca.
Míralo
NOT IN y un solo NULL
La gerencia está ordenando el menú del sitio web y pregunta qué categorías no tienen ningún producto. Espera «Alimentos» y «Hogar»: ahí solo hay subcategorías. Este es el primer intento:
Es la trampa de la lección de NULL, pero ahora NULL viene de la subconsulta y no se ve en la consulta. NOT EXISTS no compara valores: pregunta si existe tal producto, y NULL no le estorba:
Cuando la subconsulta recorre una columna que puede ser NULL, usa NOT EXISTS o añade WHERE category_id IS NOT NULL a la subconsulta.
Ejercicio
Dos tareas
1. El equipo de calidad quiere llamar a los clientes que tienen al menos un pedido cancelado.
Muestra los nombres de los clientes con al menos un pedido cancelado.
Solución
SELECT name FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.customer_id = c.id AND o.status = 'cancelled'
);WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id AND o.status = 'cancelled'). Siete clientes. También sirve id IN (SELECT customer_id FROM orders WHERE status = 'cancelled').
2. Marketing prepara una campaña «Escribe una reseña» para los productos que nadie ha reseñado todavía.
Muestra los nombres de los productos sin una sola reseña (la tabla reviews).
Solución
SELECT name FROM products p
WHERE NOT EXISTS (SELECT 1 FROM reviews r WHERE r.product_id = p.id);WHERE NOT EXISTS (SELECT 1 FROM reviews r WHERE r.product_id = p.id). 12 productos, entre ellos la tarjeta de regalo.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: IN, BETWEEN y LIKE · NULL: sin valor · Funciones de agregación: COUNT, SUM, AVG · JOIN: dos tablas en una consulta
- Continúa en: Subconsultas correlacionadas · Un informe por pasos: WITH · Árboles y secuencias: WITH RECURSIVE · Funciones de ventana
- Ejercicios sobre el tema: Subconsultas y ventanas