Subconsultas correlacionadas
Hasta ahora la subconsulta se ejecutaba una sola vez, de forma independiente. Una subconsulta correlacionada es distinta: referencia una columna de la consulta externa, así que se evalúa una vez por cada fila de fuera. Es como un bucle: para cada categoría, ejecuta la interna usando esa categoría.
-- Categorías cuyo producto más caro supera los 100
SELECT nombre
FROM categorias c
WHERE 100 < (
SELECT MAX(p.precio)
FROM productos p
WHERE p.categoria_id = c.id -- <- referencia a la fila externa "c"
)
ORDER BY nombre;
La clave es el alias: c se define fuera y se usa dentro. Eso es lo que
"correlaciona" ambas consultas.
EXISTS
EXISTS recibe una subconsulta y devuelve verdadero si esa subconsulta
produce al menos una fila (no importa qué fila: solo si existe o no). Se usa casi
siempre correlacionado, para preguntar "¿hay alguna fila relacionada?":
-- Categorías que TIENEN al menos un producto
SELECT nombre
FROM categorias c
WHERE EXISTS (
SELECT 1 FROM productos p WHERE p.categoria_id = c.id
)
ORDER BY nombre;
Por convención se escribe SELECT 1 dentro de EXISTS: como solo importa la
existencia, las columnas concretas dan igual.
Su negación, NOT EXISTS, encuentra lo contrario: categorías sin productos.
SELECT nombre
FROM categorias c
WHERE NOT EXISTS (
SELECT 1 FROM productos p WHERE p.categoria_id = c.id
)
ORDER BY nombre;
EXISTS vs IN: a menudo dan el mismo resultado, pero
EXISTSsuele ser más claro y robusto cuando hay correlación o posiblesNULL, y puede detenerse en cuanto encuentra la primera coincidencia.
Ejemplos
EXISTS: categorías con stock disponible
SELECT nombre
FROM categorias c
WHERE EXISTS (
SELECT 1 FROM productos p
WHERE p.categoria_id = c.id AND p.stock > 0
)
ORDER BY nombre;
NOT EXISTS: categorías sin ningún producto en stock
SELECT nombre
FROM categorias c
WHERE NOT EXISTS (
SELECT 1 FROM productos p
WHERE p.categoria_id = c.id AND p.stock > 0
)
ORDER BY nombre;