Subconsultas SQL: tipos, ejemplos y buenas prácticas

Una subconsulta SQL es una consulta incluida dentro de otra sentencia. Su resultado puede actuar como un valor, una lista, una tabla temporal o una condición de existencia. Permite expresar preguntas como “productos por encima del promedio” o “clientes que tienen al menos un pedido”.
La clave no es anidar por anidar, sino elegir el patrón que comunique la intención y permita al optimizador trabajar bien.
Sintaxis básica
Productos con precio superior al promedio:
SELECT
producto_id,
nombre,
precio
FROM productos
WHERE precio > (
SELECT AVG(precio)
FROM productos
);
La consulta interior devuelve un valor; la exterior lo utiliza en el filtro.
Tipos de subconsultas
Subconsulta escalar
Devuelve una fila y una columna:
SELECT
pedido_id,
total,
(SELECT AVG(total) FROM pedidos) AS promedio_global
FROM pedidos;
Si devuelve más de una fila donde se espera un escalar, el motor genera un error.
Subconsulta de lista
Devuelve varios valores y se combina con IN:
SELECT nombre
FROM clientes
WHERE cliente_id IN (
SELECT cliente_id
FROM pedidos
WHERE fecha >= '2026-01-01'
);
Subconsulta de tabla
Aparece en FROM y necesita alias:
SELECT
resumen.cliente_id,
resumen.facturacion
FROM (
SELECT
cliente_id,
SUM(total) AS facturacion
FROM pedidos
GROUP BY cliente_id
) AS resumen
WHERE resumen.facturacion > 10000;
Subconsulta correlacionada
Hace referencia a la fila de la consulta exterior:
SELECT
p.producto_id,
p.categoria_id,
p.precio
FROM productos AS p
WHERE p.precio > (
SELECT AVG(p2.precio)
FROM productos AS p2
WHERE p2.categoria_id = p.categoria_id
);
Compara cada producto con el promedio de su propia categoría.
EXISTS y NOT EXISTS
EXISTS comprueba si la subconsulta devuelve al menos una fila:
SELECT
c.cliente_id,
c.nombre
FROM clientes AS c
WHERE EXISTS (
SELECT 1
FROM pedidos AS p
WHERE p.cliente_id = c.cliente_id
AND p.estado = 'pendiente'
);
El SELECT 1 expresa que no importa el contenido, solo la existencia. El optimizador puede detener la búsqueda cuando encuentra una coincidencia.
Clientes sin pedidos:
SELECT
c.cliente_id,
c.nombre
FROM clientes AS c
WHERE NOT EXISTS (
SELECT 1
FROM pedidos AS p
WHERE p.cliente_id = c.cliente_id
);
El problema de NOT IN y NULL
Este patrón puede devolver cero filas inesperadamente:
WHERE cliente_id NOT IN (
SELECT cliente_id
FROM pedidos
)
Si la subconsulta contiene NULL, la comparación se vuelve desconocida. NOT EXISTS es más seguro para antijoins:
WHERE NOT EXISTS (
SELECT 1
FROM pedidos AS p
WHERE p.cliente_id = c.cliente_id
)
Subconsulta vs JOIN
Pedidos con el nombre del cliente:
SELECT
p.pedido_id,
c.nombre
FROM pedidos AS p
JOIN clientes AS c
ON c.cliente_id = p.cliente_id;
Un JOIN es natural cuando necesitas columnas de ambas tablas. EXISTS es natural cuando solo preguntas si hay relación y quieres evitar duplicar filas; la guía para recopilar datos con SQL cubre esos fundamentos.
| Necesidad | Patrón recomendado |
|---|---|
| Traer columnas relacionadas | JOIN |
| Comprobar existencia | EXISTS |
| Comprobar ausencia | NOT EXISTS |
| Comparar con un agregado | Subconsulta escalar |
| Organizar varias etapas | CTE |
El optimizador puede transformar patrones equivalentes; prioriza claridad y confirma con el plan.
Subconsulta vs CTE
Una CTE da nombre al resultado antes de la sentencia principal. Suele ser más legible cuando:
- el cálculo se reutiliza;
- hay varias etapas;
- existe recursividad;
- quieres probar bloques por separado.
Una subconsulta corta dentro de EXISTS, IN o una comparación puede ser más directa.
ANY y ALL
Mayor que al menos un valor:
WHERE precio > ANY (
SELECT precio
FROM productos
WHERE categoria_id = 10
)
Mayor que todos:
WHERE precio > ALL (
SELECT precio
FROM productos
WHERE categoria_id = 10
)
Revisa el comportamiento cuando la subconsulta está vacía y documenta la intención; MIN o MAX puede ser más fácil de entender en algunos casos.
Rendimiento de subconsultas
Una subconsulta correlacionada parece ejecutarse por cada fila, pero los optimizadores modernos pueden reescribirla. Aun así:
- indexa columnas de correlación;
- evita funciones sobre columnas filtradas si impiden usar índices;
- devuelve solo lo necesario;
- usa
EXISTSpara existencia; - revisa cardinalidades y el plan;
- compara con un JOIN o preagregación en datos reales.
No asumas que una forma es siempre más rápida.
Errores comunes
- Devolver varias filas en una comparación escalar.
- Usar
NOT INsin considerarNULL. - Omitir alias en subconsultas de
FROM. - Anidar muchos niveles y perder legibilidad.
- Usar
SELECT *dentro de una consulta derivada. - Duplicar filas con JOIN y corregirlas con
DISTINCTsin entender la relación. - Ejecutar filtros tarde y procesar datos innecesarios.
Preguntas frecuentes
¿Qué es una subconsulta en SQL?
Es una consulta dentro de otra sentencia cuyo resultado se utiliza como valor, lista, tabla o condición.
¿Qué es una subconsulta correlacionada?
Es una subconsulta que usa columnas de la fila exterior y, conceptualmente, se evalúa en relación con cada fila.
¿Cuándo usar EXISTS en lugar de IN?
Cuando solo necesitas comprobar existencia, especialmente con una correlación. Para ausencia, NOT EXISTS evita la trampa de NULL de NOT IN.
¿Una subconsulta es más lenta que un JOIN?
No necesariamente. El optimizador puede convertir ambas formas en planes similares. Mide con datos y plan de ejecución.
¿Puedo usar una subconsulta en SELECT?
Sí, si devuelve un valor escalar por fila. Muchas subconsultas correlacionadas en SELECT pueden ser difíciles de mantener.
¿Cuál es la diferencia entre subconsulta y CTE?
La CTE asigna un nombre temporal antes de la consulta principal; la subconsulta se escribe directamente en el lugar donde se usa.

Deja una respuesta