/

/

SQL Subconsultas (Subqueries): Guía Completa con Ejemplos

Content

SQL Subconsultas (Subqueries): Guía Completa con Ejemplos

SQL Subconsultas (Subqueries): Guía Completa con Ejemplos

¿Qué es una Subconsulta?

Una subconsulta es una consulta SQL anidada dentro de otra consulta. También se conoce como "subquery" o "consulta interna". Es una técnica poderosa para resolver problemas complejos.

Tipos de Subconsultas

1. Subconsulta Escalar (Retorna un valor)

SELECT
  nombre,
  salario,
  (SELECT AVG(salario) FROM empleados) as salario_promedio
 FROM empleados;

2. Subconsulta de Fila (Retorna una fila)

SELECT *
 FROM empleados
 WHERE (departamento_id, salario) = (
  SELECT departamento_id, MAX(salario)
  FROM empleados
  GROUP BY departamento_id
  LIMIT 1
 );

3. Subconsulta de Tabla (Retorna múltiples filas)

SELECT *
 FROM empleados
 WHERE departamento_id IN (
  SELECT id FROM departamentos WHERE activo = 1
 );

---

Ubicaciones de Subconsultas

En SELECT

SELECT
  p.nombre,
  p.precio,
  (SELECT AVG(precio) FROM productos WHERE categoria_id = p.categoria_id) as precio_promedio_categoria
 FROM productos p;

En FROM (Derived Table)

SELECT departamento, promedio_salario
 FROM (
  SELECT
  d.nombre as departamento,
  AVG(e.salario) as promedio_salario
  FROM empleados e
  JOIN departamentos d ON e.departamento_id = d.id
  GROUP BY d.id, d.nombre
 ) as resumen
 WHERE promedio_salario > 50000;

En WHERE

SELECT *
 FROM productos
 WHERE precio > (SELECT AVG(precio) FROM productos);

En HAVING

SELECT categoria_id, COUNT(*) as total
 FROM productos
 GROUP BY categoria_id
 HAVING COUNT(*) > (
  SELECT AVG(cantidad)
  FROM (
  SELECT COUNT(*) as cantidad
  FROM productos
  GROUP BY categoria_id
  ) as conteo
 );

---

Operadores con Subconsultas

IN / NOT IN

-- Clientes que han hecho compras
 SELECT * FROM clientes
 WHERE id IN (SELECT DISTINCT cliente_id FROM pedidos);


EXISTS / NOT EXISTS

-- Más eficiente que IN para tablas grandes
 SELECT * FROM clientes c
 WHERE EXISTS (
  SELECT 1 FROM pedidos p WHERE p.cliente_id = c.id
 );

ANY / SOME

-- Empleados que ganan más que algún gerente
 SELECT * FROM empleados
 WHERE salario > ANY (
  SELECT salario FROM empleados WHERE puesto = 'Gerente'
 );

ALL

-- Empleados que ganan más que todos los gerentes
 SELECT * FROM empleados
 WHERE salario > ALL (
  SELECT salario FROM empleados WHERE puesto = 'Gerente'
 );

---

Subconsultas Correlacionadas

Una subconsulta correlacionada hace referencia a la consulta externa:

-- Empleados que ganan más que el promedio de su departamento
 SELECT e.nombre, e.salario, e.departamento_id
 FROM empleados e
 WHERE e.salario > (
  SELECT AVG(salario)
  FROM empleados
  WHERE departamento_id = e.departamento_id
 );

Ejemplo: Top N por Grupo

-- Los 3 productos más caros de cada categoría
 SELECT *
 FROM productos p1
 WHERE (
  SELECT COUNT(*)
  FROM productos p2
  WHERE p2.categoria_id = p1.categoria_id
  AND p2.precio > p1.precio
 ) <

---

Casos de Uso Prácticos

1. Encontrar Duplicados

SELECT *
 FROM clientes c
 WHERE (
  SELECT COUNT(*)
  FROM clientes
  WHERE email = c.email
 ) > 1;

2. Segunda Mejor Opción

-- Segundo producto más caro
 SELECT *
 FROM productos
 WHERE precio = (
  SELECT MAX(precio)
  FROM productos
  WHERE precio < (SELECT MAX(precio) FROM productos)
 );

3. Comparación con Período Anterior

SELECT
  mes,
  ventas,
  (SELECT ventas FROM ventas_mensuales WHERE mes = DATE_SUB(vm.mes, INTERVAL 1 MONTH)) as ventas_mes_anterior
 FROM ventas_mensuales vm;

4. Productos Sin Ventas

SELECT *
 FROM productos p
 WHERE NOT EXISTS (
  SELECT 1
  FROM detalle_pedidos dp
  WHERE dp.producto_id = p.id
 );

---

Subconsultas vs JOINs

A menudo, las subconsultas pueden reescribirse como JOINs:

Con Subconsulta

SELECT *
 FROM empleados
 WHERE departamento_id IN (
  SELECT id FROM departamentos WHERE ubicacion = 'Madrid'
 );

Con JOIN

SELECT e.*
 FROM empleados e
 JOIN departamentos d ON e.departamento_id = d.id
 WHERE d.ubicacion = 'Madrid';

¿Cuándo Usar Cada Una?

| Usa Subconsulta | Usa JOIN |

|-----------------|----------|

| Verificar existencia (EXISTS) | Necesitas datos de ambas tablas |

| Comparar con agregados | Múltiples relaciones |

| Lógica más clara | Mejor performance en muchos casos |

| Consultas de eliminación/actualización | Consultas complejas con varios filtros |


---

CTEs: Alternativa Moderna

Common Table Expressions (WITH) hacen las consultas más legibles:

WITH ventas_por_vendedor AS (
  SELECT
  vendedor_id,
  SUM(total) as total_ventas
  FROM pedidos
  GROUP BY vendedor_id
 ),
 promedio_ventas AS (
  SELECT AVG(total_ventas) as promedio
  FROM ventas_por_vendedor
 )
 SELECT v.vendedor_id, v.total_ventas
 FROM ventas_por_vendedor v, promedio_ventas p
 WHERE v.total_ventas > p.promedio;

---

Errores Comunes

Error 1: Subconsulta Retorna Múltiples Filas

-- Error: más de un valor retornado
 SELECT * FROM empleados
 WHERE salario = (SELECT salario FROM empleados WHERE departamento_id = 1);


Error 2: NULL con NOT IN

-- Problema: si hay NULLs, NOT IN puede no retornar resultados
 SELECT * FROM clientes
 WHERE id NOT IN (SELECT cliente_id FROM pedidos); -- puede fallar si hay NULL


Error 3: Performance en Subconsultas Correlacionadas

Las subconsultas correlacionadas se ejecutan una vez por cada fila. Considera reescribir como JOIN.

---

Optimización

1. Usa EXISTS en lugar de IN para tablas grandes 2. Materializa subconsultas con CTEs cuando se usan múltiples veces 3. Revisa el plan de ejecución con EXPLAIN 4. Considera índices en las columnas de la subconsulta

Conclusión

Las subconsultas son herramientas esenciales para resolver problemas complejos en SQL. Dominarlas te permite escribir consultas más expresivas y poderosas.

---

Consejo: Usa AI2sql para generar subconsultas complejas automáticamente y aprende de las diferentes técnicas utilizadas.

Share this

More Articles