Esta es una muy buena pregunta, así que decidí escribir un artículo muy detallado sobre este tema en mi blog.
Modelo de tabla de base de datos
Supongamos que tenemos las siguientes dos tablas en nuestra base de datos, que forman una relación de tabla de uno a muchos.
La student
tabla es el padre, y elstudent_grade
tabla secundaria, ya que tiene una columna de clave externa student_id que hace referencia a la columna de clave principal id en la tabla del alumno.
El student table
contiene los siguientes dos registros:
| id | first_name | last_name | admission_score |
|----|------------|-----------|-----------------|
| 1 | Alice | Smith | 8.95 |
| 2 | Bob | Johnson | 8.75 |
Y, la student_grade
tabla almacena las calificaciones que recibieron los estudiantes:
| id | class_name | grade | student_id |
|----|------------|-------|------------|
| 1 | Math | 10 | 1 |
| 2 | Math | 9.5 | 1 |
| 3 | Math | 9.75 | 1 |
| 4 | Science | 9.5 | 1 |
| 5 | Science | 9 | 1 |
| 6 | Science | 9.25 | 1 |
| 7 | Math | 8.5 | 2 |
| 8 | Math | 9.5 | 2 |
| 9 | Math | 9 | 2 |
| 10 | Science | 10 | 2 |
| 11 | Science | 9.4 | 2 |
SQL EXISTE
Digamos que queremos que todos los estudiantes que hayan recibido un grado 10 en la clase de matemáticas.
Si solo estamos interesados en el identificador de estudiante, entonces podemos ejecutar una consulta como esta:
SELECT
student_grade.student_id
FROM
student_grade
WHERE
student_grade.grade = 10 AND
student_grade.class_name = 'Math'
ORDER BY
student_grade.student_id
Pero, la aplicación está interesada en mostrar el nombre completo de a student
, no solo el identificador, por lo que también necesitamos información de la student
tabla.
Para filtrar los student
registros que tienen una calificación de 10 en matemáticas, podemos usar el operador EXISTS SQL, así:
SELECT
id, first_name, last_name
FROM
student
WHERE EXISTS (
SELECT 1
FROM
student_grade
WHERE
student_grade.student_id = student.id AND
student_grade.grade = 10 AND
student_grade.class_name = 'Math'
)
ORDER BY id
Al ejecutar la consulta anterior, podemos ver que solo se selecciona la fila Alice:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
La consulta externa selecciona las student
columnas de fila que estamos interesados en devolver al cliente. Sin embargo, la cláusula WHERE está utilizando el operador EXISTS con una subconsulta interna asociada.
El operador EXISTS devuelve verdadero si la subconsulta devuelve al menos un registro y falso si no se selecciona ninguna fila. El motor de base de datos no tiene que ejecutar la subconsulta por completo. Si se coincide con un solo registro, el operador EXISTS devuelve verdadero y se selecciona la otra fila de consulta asociada.
La subconsulta interna está correlacionada porque la columna student_id de la student_grade
tabla se compara con la columna id de la tabla externa del estudiante.
SQL NO EXISTE
Consideremos que queremos seleccionar a todos los estudiantes que no tengan una calificación inferior a 9. Para esto, podemos usar NOT EXISTS, que niega la lógica del operador EXISTS.
Por lo tanto, el operador NO EXISTE devuelve verdadero si la subconsulta subyacente no devuelve ningún registro. Sin embargo, si la subconsulta interna coincide con un solo registro, el operador NO EXISTE devolverá falso y la ejecución de la subconsulta puede detenerse.
Para hacer coincidir todos los registros de estudiantes que no tienen un student_grade asociado con un valor inferior a 9, podemos ejecutar la siguiente consulta SQL:
SELECT
id, first_name, last_name
FROM
student
WHERE NOT EXISTS (
SELECT 1
FROM
student_grade
WHERE
student_grade.student_id = student.id AND
student_grade.grade < 9
)
ORDER BY id
Al ejecutar la consulta anterior, podemos ver que solo coincide el registro de Alice:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
Por lo tanto, la ventaja de utilizar los operadores SQL EXISTS y NOT EXISTS es que la ejecución de la subconsulta interna se puede detener siempre que se encuentre un registro coincidente.