...

Subconsultas en SQL: cuándo usar IN, EXISTS y subconsultas correlacionadas

Las subconsultas (o subqueries) permiten ejecutar una consulta dentro de otra. Son una herramienta poderosa para expresar lógica compleja —por ejemplo, filtrar resultados usando agregados, comprobar existencia de registros o construir tablas derivadas— sin necesidad de crear vistas temporales. En este artículo veremos tipos de subconsultas (no correlacionadas, correlacionadas, escalares y en FROM), ejemplos comentados, implicaciones de rendimiento y diferencias entre motores (SQL Server, PostgreSQL, MySQL, SQLite). Todos los ejemplos son ejecutables en db-fiddle.com.


¿Qué es una subconsulta?

Una subconsulta es una consulta SQL que aparece dentro de otra instrucción SQL: en la cláusula WHERE, SELECT, FROM, o HAVING. Puede devolver:

  • Un solo valor (subconsulta escalar).
  • Una columna de valores (usada con IN, ANY, ALL).
  • Un conjunto de filas/columnas (usada en FROM como tabla derivada).

Tipos de subconsultas y sintaxis básica

1. Subconsulta no correlacionada (independiente)

Se evalúa una vez y su resultado se usa en la consulta exterior.

-- Ejemplo: empleados con salario mayor al promedio general
SELECT nombre, salario
FROM empleados
WHERE salario > (
  SELECT AVG(salario) FROM empleados
);

2. Subconsulta correlacionada

Hace referencia a una columna de la consulta exterior; se evalúa por cada fila de la consulta externa.

-- Empleados con salario mayor que el promedio de su propio departamento
SELECT e1.nombre, e1.salario, e1.id_departamento
FROM empleados e1
WHERE e1.salario > (
  SELECT AVG(e2.salario)
  FROM empleados e2
  WHERE e2.id_departamento = e1.id_departamento
);

3. Subconsulta en SELECT (subconsulta escalar)

Devuelve un valor por fila y puede usarse como columna calculada.

SELECT e.nombre,
       (SELECT nombre_departamento
        FROM departamentos d
        WHERE d.id_departamento = e.id_departamento
       ) AS departamento
FROM empleados e;

4. Subconsulta en FROM (tabla derivada)

La subconsulta actúa como una tabla temporal que podemos unir o consultar.

SELECT t.id_departamento, t.total_empleados
FROM (
  SELECT id_departamento, COUNT(*) AS total_empleados
  FROM empleados
  GROUP BY id_departamento
) AS t
JOIN departamentos d ON t.id_departamento = d.id_departamento;

5. EXISTS / NOT EXISTS

Se usa para comprobar existencia de filas (eficiente en muchos motores).

-- Departamentos que tienen al menos un empleado
SELECT d.nombre_departamento
FROM departamentos d
WHERE EXISTS (
  SELECT 1 FROM empleados e WHERE e.id_departamento = d.id_departamento
);

Código de ejemplo (estructura y datos)

-- Tablas
CREATE TABLE departamentos (
  id_departamento INTEGER PRIMARY KEY,
  nombre_departamento TEXT NOT NULL
);

CREATE TABLE empleados (
  id_empleado INTEGER PRIMARY KEY,
  nombre TEXT NOT NULL,
  salario DECIMAL(12,2) NOT NULL,
  id_departamento INTEGER
);

-- Datos
INSERT INTO departamentos (id_departamento, nombre_departamento) VALUES
(1, 'Ventas'),
(2, 'Marketing'),
(3, 'Finanzas'),
(4, 'Desarrollo');

INSERT INTO empleados (id_empleado, nombre, salario, id_departamento) VALUES
(1, 'Ana', 75000, 1),
(2, 'Luis', 90000, 1),
(3, 'Marta', 60000, 2),
(4, 'Carlos', 50000, 3),
(5, 'Sofía', 88000, 1),
(6, 'Diego', 45000, NULL),
(7, 'Laura', 72000, 4),
(8, 'Pedro', 48000, 2);

Ejemplos prácticos comentados

A — Subconsulta escalar en WHERE

-- Empleados con salario mayor que el promedio global
SELECT nombre, salario
FROM empleados
WHERE salario > (
  SELECT AVG(salario) FROM empleados
);

Comentario: subconsulta no correlacionada que devuelve AVG(salario). Se evalúa una vez.

B — Subconsulta correlacionada para comparación por grupo

-- Empleados que superan el salario promedio de su propio departamento
SELECT e1.nombre, e1.salario, e1.id_departamento
FROM empleados e1
WHERE e1.id_departamento IS NOT NULL
  AND e1.salario > (
    SELECT AVG(e2.salario)
    FROM empleados e2
    WHERE e2.id_departamento = e1.id_departamento
  );

Comentario: la subconsulta depende de e1.id_departamento y es evaluada por fila (correlacionada).

C — EXISTS vs IN

-- Departamentos con empleados (EXISTS)
SELECT d.nombre_departamento
FROM departamentos d
WHERE EXISTS (
  SELECT 1 FROM empleados e WHERE e.id_departamento = d.id_departamento
);

-- Empleados cuyo departamento está dentro de una lista producida por subconsulta (IN)
SELECT nombre
FROM empleados
WHERE id_departamento IN (
  SELECT id_departamento FROM departamentos WHERE nombre_departamento LIKE 'V%'
);

Comentario: EXISTS suele ser más eficiente cuando la subconsulta devuelve muchas filas; IN es legible para conjuntos pequeños. Evitar IN si hay NULLs en la subconsulta y la lógica importa.

D — Subconsulta en FROM (tabla derivada)

-- Total de empleados por departamento y unir con nombres
SELECT d.nombre_departamento, t.total_empleados
FROM (
  SELECT id_departamento, COUNT(*) AS total_empleados
  FROM empleados
  GROUP BY id_departamento
) t
LEFT JOIN departamentos d ON t.id_departamento = d.id_departamento;

Comentario: útil para cálculos intermedios y para componer consultas complejas.

E — Uso de ANY / ALL (comparaciones)

-- Empleados cuyo salario es mayor que todos los salarios del departamento 2
SELECT nombre, salario
FROM empleados
WHERE salario > ALL (
  SELECT salario FROM empleados WHERE id_departamento = 2
);

Comentario: ALL exige que la condición sea verdadera frente a todos los valores devueltos; ANY (o SOME) es verdadera si la condición es verdadera frente a alguno de los valores.


Performance y buenas prácticas con subconsultas

Cuando trabajas con subconsultas en SQL, es importante pensar en el rendimiento (performance). Aquí tienes algunos consejos prácticos:

1. Tipos de subconsultas

  • Subconsulta no correlacionada:
    Se ejecuta una sola vez. Es ideal para cálculos generales, como sacar el promedio total o el máximo global.
    • Ejemplo: Obtener a los empleados que ganan más que el salario promedio.
  • Subconsulta correlacionada:
    Se ejecuta una vez por cada fila de la consulta principal. Esto puede ser muy lento si la tabla es grande.
    A veces es mejor reescribirla como un JOIN para mejorar la velocidad.

2. EXISTS vs IN

  • EXISTS suele ser más rápido que IN, especialmente cuando:
    • La subconsulta devuelve muchos datos.
    • Hay posibilidad de que existan valores NULL.

Regla rápida: si dudas entre IN y EXISTS, prueba primero con EXISTS.


3. JOIN vs subconsultas correlacionadas

  • Los JOINs suelen ser más eficientes con datos grandes.
  • Si tu subconsulta está repitiéndose para cada fila, considera reescribirla como un JOIN.

4. Optimización básica

  • Filtra los datos lo más pronto posible con WHERE.
  • Crea índices en las columnas que usas para filtrar o unir tablas.
  • Usa EXPLAIN o EXPLAIN ANALYZE para ver cómo el motor ejecuta tu consulta.

5. Diferencias según el motor de base de datos

  • PostgreSQL: tiene muy buen optimizador y soporta LATERAL para subconsultas avanzadas.
  • SQL Server: cuenta con CROSS APPLY y OUTER APPLY (similar a LATERAL).
  • MySQL: versiones modernas (8+) optimizan mejor, pero en versiones anteriores a veces conviene reescribir en JOIN.
  • SQLite: excelente para aprender, pero menos eficiente con datos muy grandes.

Consejo: Siempre revisa la documentación de tu motor para ver qué soporta y cómo optimiza.


6. Buenas prácticas

  • Filtra primero, trabaja la subconsulta después.
  • Evita subconsultas correlacionadas en tablas grandes.
  • Prefiere EXISTS sobre IN cuando hay muchos datos.
  • Asegúrate de que las subconsultas escalares devuelvan solo un valor.
  • Documenta por qué elegiste una subconsulta en lugar de un JOIN (a veces la claridad es más importante que la velocidad).

Conclusión

Las subconsultas son una herramienta muy útil en SQL. Te permiten:

  • Encapsular lógica para mantener consultas más organizadas.
  • Comparar datos con valores calculados, como promedios o máximos.
  • Verificar si existen ciertos registros.
  • Crear tablas temporales para consultas más complejas.

Sin embargo, no abuses de ellas, sobre todo de las subconsultas correlacionadas, ya que pueden volver tu consulta lenta.

Aprende a elegir entre subconsultas, JOINs o funciones como APPLY/LATERAL, dependiendo de lo que necesites y del motor de base de datos que estés usando.

Practica los ejemplos en db-fiddle.com para interiorizar la lógica y medir rendimiento real.

Deja un comentario

Seraphinite AcceleratorOptimized by Seraphinite Accelerator
Turns on site high speed to be attractive for people and search engines.