CodeGym /Cursos /SQL SELF /Ejemplos de consultas anidadas complejas: combinación de ...

Ejemplos de consultas anidadas complejas: combinación de EXISTS, IN, HAVING

SQL SELF
Nivel 14 , Lección 3
Disponible

Ejemplos de consultas anidadas complejas: combinación de EXISTS, IN, HAVING

¡Enhorabuena, hemos llegado al punto donde esto se pone realmente interesante! Hoy vamos a ver cómo combinar diferentes tipos de subconsultas para resolver tareas complicadas. EXISTS, IN, HAVING — ese trío mágico que te hará sentir como un mago de las bases de datos. Vamos a sacar datos de una tabla, filtrarlos usando otra, agruparlos y luego filtrar los grupos. Y como bonus, veremos algunos trucos para hacer las consultas más eficientes.

Vamos a empezar planteando una tarea general que iremos resolviendo a lo largo de la lección.

Planteamiento del problema

Supongamos que tenemos una base de datos de una universidad con tres tablas:

Tabla students

id name group_id
1 Otto 101
2 Maria 101
3 Alex 102
4 Anna 103

Tabla courses

id name
1 Matemáticas
2 Programación
3 Filosofía

Tabla enrollments

student_id course_id grade
1 1 90
1 2 NULL
2 1 85
3 3 70

Hay que seleccionar todos los estudiantes que:

  1. Están inscritos al menos en un curso EXISTS.
  2. No tienen nota en al menos uno de los cursos en los que están inscritos IN.
  3. Pertenecen a grupos donde la nota media es mayor que 80 HAVING.

Solución usando EXISTS y IN

Paso 1: Comprobar estudiantes inscritos (EXISTS). Empezamos con la condición más sencilla. Queremos saber quién está inscrito al menos en un curso. Para esto usamos EXISTS.

SELECT name
FROM students s
WHERE EXISTS (
  SELECT 1
  FROM enrollments e
  WHERE e.student_id = s.id
);
  1. La consulta externa selecciona los nombres de la tabla students.
  2. En la subconsulta comprobamos si existen registros en la tabla enrollments que correspondan al estudiante de la consulta externa (WHERE e.student_id = s.id).
  3. SELECT 1 se usa para indicar que solo nos importa la existencia del registro, no su contenido.

Resultado:

name
Otto
Maria
Alex

Ahora ya sabemos quiénes están inscritos en cursos. Pero queremos más. Queremos filtrarlos por ausencia de notas.

Paso 2: Comprobar ausencia de nota (IN + NULL). Ahora añadimos un filtro: solo queremos los estudiantes que no tienen nota en al menos uno de sus cursos. Aquí nos ayudan IN y saber cómo funciona NULL.

SELECT name
FROM students s
WHERE id IN (
  SELECT e.student_id
  FROM enrollments e
  WHERE e.grade IS NULL
);
  1. En la consulta externa seleccionamos los nombres de los estudiantes.
  2. La subconsulta genera una lista de student_id de la tabla enrollments donde grade IS NULL.

Resultado:

name
Otto

Así que Otto es el único estudiante que tiene un curso sin nota. ¡Qué dramático! Pero aún no hemos terminado: solo queremos los grupos donde la nota media es mayor que 80.

Solución usando HAVING

Paso 3: Agrupar y filtrar con HAVING.

Ahora toca unirlo todo. Necesitamos:

  1. Calcular la nota media de cada grupo.
  2. Filtrar los grupos con nota media mayor que 80.
  3. Mostrar los estudiantes de esos grupos, cumpliendo las condiciones anteriores.
SELECT name
FROM students s
WHERE s.group_id IN (
  SELECT group_id
  FROM students
  JOIN enrollments ON students.id = enrollments.student_id
  WHERE grade IS NOT NULL
  GROUP BY group_id
  HAVING AVG(grade) > 80
)
AND id IN (
  SELECT e.student_id
  FROM enrollments e
  WHERE e.grade IS NULL
);
  1. La consulta externa selecciona los nombres de los estudiantes que cumplen todas las condiciones.
  2. La primera subconsulta en WHERE devuelve la lista de group_id para los grupos con nota media mayor que 80.
    • Unimos students con enrollments para obtener las notas.
    • Filtramos solo los registros donde grade IS NOT NULL.
    • Agrupamos los datos por group_id.
    • Usamos HAVING para filtrar los grupos.
  3. La segunda subconsulta en WHERE comprueba que el estudiante tiene al menos un curso sin nota.
  4. Ambas partes de la condición se combinan con AND.

Resultado:

name
Otto

Así que hemos descubierto que Otto no solo es el único estudiante sin nota, sino que además pertenece a un grupo que destaca por sus éxitos.

Comparación de enfoques: EXISTS vs IN

EXISTS va genial cuando solo quieres comprobar rápido si existen registros. Es eficiente porque para la búsqueda en cuanto encuentra el primero. Esto es clave en tablas grandes.

Por otro lado, IN es útil cuando te interesa el contenido de los datos. Por ejemplo, si sacas una lista de identificadores (id) para filtrar después. Pero ojo, IN puede ser lento si la subconsulta devuelve muchos valores.

Cuándo usar HAVING

Para datos agregados, cuando necesitas filtrar según los resultados, HAVING es la mejor opción. Pero si puedes mover la condición a WHERE (por ejemplo, filtrando por columna), la consulta será más simple y rápida.

Ejemplo completo

Para afianzar, veamos otro ejemplo: seleccionar los grupos donde al menos un estudiante tiene nota menor que 75, pero que no están inscritos en el curso "Filosofía".

Recordemos nuestras tablas:

Tabla students

id name group_id
1 Otto 101
2 Maria 101
3 Alex 102
4 Anna 103

Tabla courses

id name
1 Matemáticas
2 Programación
3 Filosofía

Tabla enrollments

student_id course_id grade
1 1 90
1 2 NULL
2 1 85
3 3 70
SELECT DISTINCT group_id
FROM students s
WHERE group_id IN (
  SELECT s.group_id
  FROM students s
  JOIN enrollments e ON s.id = e.student_id
  WHERE e.grade < 75
)
AND group_id NOT IN (
  SELECT s.group_id                                 -- subconsulta de primer nivel
  FROM students s
  JOIN enrollments e ON s.id = e.student_id
  WHERE e.course_id = (
    SELECT id FROM courses WHERE name = 'Filosofía' -- subconsulta de segundo nivel :P
  )
);
  1. La primera subconsulta selecciona los grupos donde hay estudiantes con nota menor que 75.
  2. La segunda subconsulta excluye los grupos relacionados con el curso "Filosofía".
  3. Combinamos las condiciones usando IN y NOT IN para obtener el resultado final.

Resultado:

group_id
101

¿Qué tan útil es esto?

En la vida real, estos enfoques te salvan cuando tienes que analizar relaciones complejas de datos. Por ejemplo:

  • En analítica para destacar grupos "especiales" de clientes (VIP, problemáticos, etc.).
  • En desarrollo de sistemas de recomendación, donde filtramos usuarios por muchos criterios.
  • En entrevistas, cuando te piden optimizar una consulta SQL complicada.

¡Practica! Así es como se llega a ser crack.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION