Essa é uma pergunta muito boa, então decidi escrever um artigo muito detalhado sobre esse tópico no meu blog.
Modelo de tabela de banco de dados
Vamos supor que temos as duas tabelas a seguir em nosso banco de dados, que formam um relacionamento de tabela um para muitos.
A student
tabela é o pai e a student_grade
tabela filha, pois possui uma coluna Chave estrangeira student_id que faz referência à coluna Chave primária id na tabela do aluno.
O student table
contém os dois registros a seguir:
| id | first_name | last_name | admission_score |
|----|------------|-----------|-----------------|
| 1 | Alice | Smith | 8.95 |
| 2 | Bob | Johnson | 8.75 |
E, a student_grade
tabela armazena as notas que os alunos receberam:
| 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 EXISTS
Digamos que queremos que todos os alunos que tenham recebido nota 10 na aula de matemática.
Se estivermos interessados apenas no identificador de aluno, podemos executar uma 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
Mas, o aplicativo está interessado em exibir o nome completo de a student
, não apenas o identificador, por isso precisamos de informações da student
tabela também.
Para filtrar os student
registros que possuem nota 10 em matemática, podemos usar o operador EXISTS SQL, assim:
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
Ao executar a consulta acima, podemos ver que apenas a linha Alice está selecionada:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
A consulta externa seleciona as student
colunas da linha que estamos interessados em retornar ao cliente. No entanto, a cláusula WHERE está usando o operador EXISTS com uma subconsulta interna associada.
O operador EXISTS retornará true se a subconsulta retornar pelo menos um registro e false se nenhuma linha for selecionada. O mecanismo do banco de dados não precisa executar a subconsulta inteiramente. Se um único registro for correspondido, o operador EXISTS retornará true e a outra linha de consulta associada será selecionada.
A subconsulta interna é correlacionada porque a coluna student_id da student_grade
tabela é comparada com a coluna id da tabela externa do aluno.
SQL NÃO EXISTE
Vamos considerar que queremos selecionar todos os alunos que não têm nota inferior a 9. Para isso, podemos usar NOT EXISTS, o que nega a lógica do operador EXISTS.
Portanto, o operador NOT EXISTS retornará true se a subconsulta subjacente não retornar nenhum registro. No entanto, se um único registro for correspondido pela subconsulta interna, o operador NOT EXISTS retornará false e a execução da subconsulta poderá ser interrompida.
Para corresponder a todos os registros de alunos que não tenham associado student_grade a um valor menor que 9, podemos executar a seguinte 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
Ao executar a consulta acima, podemos ver que apenas o registro de Alice é correspondido:
| id | first_name | last_name |
|----|------------|-----------|
| 1 | Alice | Smith |
Portanto, a vantagem de usar os operadores SQL EXISTS e NOT EXISTS é que a execução da subconsulta interna pode ser interrompida enquanto for encontrado um registro correspondente.