¡Bienvenido a una nueva lección de SQL! Hoy vamos a conocer a los operadores más discretos pero increíblemente potentes — EXISTS y NOT EXISTS. Imagina a un espía que no deja huellas, pero te dice al instante: "Sí, el objeto existe" o "No, aquí no hay nada". Estos operadores no devuelven datos directamente, pero te permiten hacer comprobaciones lógicas súper precisas en tus consultas.
Vamos con lo básico. EXISTS es un operador que comprueba si existen filas en el resultado de una subconsulta. Si la subconsulta devuelve al menos una fila, la condición EXISTS devuelve TRUE, si no — FALSE.
SELECT 1
WHERE EXISTS (
SELECT *
FROM students
WHERE grade > 3.5
);
Como ves, no nos interesan los datos de la subconsulta, solo si existen esas filas. Si hay al menos una fila que cumple la condición, la consulta devuelve 1.
Sintaxis de EXISTS
La sintaxis de EXISTS es sencilla:
SELECT columnas
FROM tabla
WHERE EXISTS (
SELECT 1
FROM otra_tabla
WHERE condición
);
Explicación:
- La subconsulta dentro de
EXISTSpuede ser cualquier consulta. - El resultado de la subconsulta es lo que determina si devuelve
TRUEoFALSE.
Ejemplo: ¿Hay estudiantes con nota mayor que 4?
Imagina la tabla students:
| id | name | grade |
|---|---|---|
| 1 | Otto | 3.2 |
| 2 | Anna | 4.7 |
| 3 | Dan | 5.0 |
| 4 | Lina | 2.9 |
Supón que queremos comprobar si existen estudiantes con nota mayor que 4. Usamos esta consulta:
SELECT '¡Hay estudiantes con nota alta!'
WHERE EXISTS (
SELECT 1
FROM students
WHERE grade > 4
);
Resultado:
¡Hay estudiantes con nota alta!
¿Por qué EXISTS es más rápido que IN?
La principal ventaja de EXISTS es que para la ejecución de la subconsulta en cuanto encuentra la primera coincidencia. O sea, si tienes una condición que solo quiere saber si existen datos, EXISTS puede ser súper eficiente.
Por ejemplo, imagina que la tabla students tiene millones de filas, pero solo buscas una coincidencia (grade > 4). En cuanto SQL encuentra la primera fila que cumple, la consulta termina.
Uso de NOT EXISTS
Ahora hablemos de NOT EXISTS. Este operador es el opuesto de EXISTS. Devuelve TRUE si la subconsulta no devuelve ninguna fila.
Ejemplo: encontrar estudiantes sin notas (NULL)
Supón que en nuestra tabla hay estudiantes que aún no tienen nota:
| id | name | grade |
|---|---|---|
| 1 | Otto | NULL |
| 2 | Anna | 4.7 |
| 3 | Dan | 5.0 |
| 4 | Lina | NULL |
Queremos seleccionar todos los estudiantes sin nota. Usamos NOT EXISTS:
SELECT *
FROM students s
WHERE NOT EXISTS (
SELECT 1
FROM students
WHERE grade IS NOT NULL
AND id = s.id
);
Resultado:
| id | name | grade |
|---|---|---|
| 1 | Otto | NULL |
| 4 | Lina | NULL |
Comparando EXISTS y IN
A veces parece que EXISTS y IN hacen lo mismo. A primera vista sí, pero hay matices. Sobre todo si aparece un NULL por ahí. Entonces el comportamiento de IN puede ser inesperado, y EXISTS te salva.
Vamos a verlo con un ejemplo.
Tabla courses (cursos que puedes hacer):
| course_id | name |
|---|---|
| 1 | Matemáticas |
| 2 | Historia |
Y los estudiantes:
| student_id | name |
|---|---|
| 1 | Alex Lin |
| 2 | Anna Song |
| 3 | Maria Chi |
| 4 | Dan Seth |
| 5 | Shadow Moon |
Tabla enrollments (quién se ha apuntado a qué curso):
| student_id | course_id |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | NULL |
Queremos seleccionar los nombres de los cursos en los que alguien está apuntado. Parece fácil.
Usando IN:
SELECT name
FROM courses
WHERE course_id IN (
SELECT course_id
FROM enrollments
);
Parece que debería funcionar. Pero si en enrollments hay un NULL en courseid, como con Maria Chi, IN puede devolver... ¡nada! Porque NULL hace que la subconsulta sea "indefinida", y SQL se lía: ¿y si NULL es justo el courseid que buscamos?
Usando EXISTS:
SELECT name
FROM courses c
WHERE EXISTS (
SELECT 1
FROM enrollments e
WHERE c.course_id = e.course_id
);
Pero EXISTS comprueba: "¿Hay al menos una fila donde course_id coincide?" — y ya está. No se asusta si hay un NULL cerca, porque busca coincidencias concretas, no una lista de valores.
En resumen: si puede haber NULL en la subconsulta, mejor usa EXISTS para no llevarte sorpresas.
Ejemplos de casos reales
Tabla students:
| id | name |
|---|---|
| 1 | Alex Lin |
| 2 | Anna Song |
| 3 | Maria Chi |
| 4 | Dan Seth |
| 5 | Shadow Moon |
Tabla enrollments:
| student_id | course_id |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | NULL |
Ejemplo 1. Estudiantes apuntados a cursos
Vamos a buscar a los que ya han aparecido en algún curso (aunque sea raro, como Maria Chi):
SELECT name
FROM students s
WHERE EXISTS (
SELECT 1
FROM enrollments e
WHERE s.id = e.student_id
);
Resultado:
Alex Lin
Anna Song
Maria Chi
Si el estudiante aparece de alguna forma en enrollments — sale en la consulta, aunque su course_id sea raro.
Ejemplo 2. Estudiantes sin cursos
Ahora vamos a buscar a los que solo existen en el sistema — pero no están apuntados a nada:
SELECT name
FROM students s
WHERE NOT EXISTS (
SELECT 1
FROM enrollments e
WHERE s.id = e.student_id
);
Resultado:
Dan Seth
Shadow Moon
Parece que estos dos aún no han encontrado un curso que les mole. O simplemente se les ha olvidado apuntarse :)
Ejemplo 3. Seleccionar cursos con más de 5 estudiantes registrados
Tabla courses:
| course_id | name |
|---|---|
| 1 | Matemáticas |
| 2 | Historia |
| 3 | Biología |
| 4 | Filosofía |
Tabla enrollments:
| student_id | course_id |
|---|---|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
| 6 | 1 |
| 7 | 2 |
| 8 | 2 |
| 9 | 2 |
| 10 | NULL |
Queremos encontrar los cursos en los que hay más de cinco estudiantes apuntados. Aquí EXISTS pregunta: "¿Hay algún grupo de filas para este curso donde haya más de cinco estudiantes?"
SELECT name
FROM courses c
WHERE EXISTS (
SELECT 1
FROM enrollments e
WHERE c.course_id = e.course_id
GROUP BY e.course_id
HAVING COUNT(*) > 5
);
Resultado:
Matemáticas
Solo el curso "Matemáticas" (course_id = 1) tiene seis estudiantes apuntados. Los demás cursos aún no son tan populares.
Errores comunes usando EXISTS y NOT EXISTS
- Malentender la sintaxis de la subconsulta. Siempre revisa que la subconsulta haga referencia correctamente a la tabla externa.
- Olvidar comprobar
NULL. Incluso usandoEXISTS, a veces tienes que indicar explícitamente cómo tratar losNULL. - No tener un índice en los campos de la subconsulta. Esto puede hacer que la consulta sea mucho más lenta.
¡Y eso es todo por hoy! Ahora ya sabes cómo usar EXISTS y NOT EXISTS para comprobar la existencia de datos, y las diferencias entre estos operadores y IN. En la próxima lección seguiremos profundizando en subconsultas, viendo cómo usarlas en SELECT para trabajar con datos agregados.
GO TO FULL VERSION