Seja bem-vindo(a) à nova aula de SQL! Hoje a gente vai conhecer os operadores mais discretos, mas super poderosos — EXISTS e NOT EXISTS. Imagina um espião que não deixa rastros, mas te fala na lata: "Sim, o objeto existe" ou "Não, aqui tá vazio". Esses operadores não devolvem dados direto, mas deixam você fazer checagens lógicas certeiras nas queries.
Vamos começar do básico. EXISTS — é um operador que verifica se existem registros no resultado de uma subquery. Se a subquery retorna pelo menos um registro, a condição EXISTS devolve TRUE, senão — FALSE.
SELECT 1
WHERE EXISTS (
SELECT *
FROM students
WHERE grade > 3.5
);
Como você viu, a gente não tá nem aí pros dados da subquery, só quer saber se tem linhas que batem. Se tiver pelo menos um registro que bate, a query retorna 1.
Sintaxe do EXISTS
A sintaxe do EXISTS é simples:
SELECT colunas
FROM tabela
WHERE EXISTS (
SELECT 1
FROM outra_tabela
WHERE condicao
);
Explicando:
- A subquery dentro do
EXISTSpode ser qualquer query. - É o resultado da subquery que define se vai voltar
TRUEouFALSE.
Exemplo: Tem estudantes com nota maior que 4?
Imagina a tabela students:
| id | name | grade |
|---|---|---|
| 1 | Otto | 3.2 |
| 2 | Anna | 4.7 |
| 3 | Dan | 5.0 |
| 4 | Lina | 2.9 |
Vamos supor que a gente quer saber se existem estudantes com nota maior que 4. Usamos essa query:
SELECT 'Tem estudantes com nota alta!'
WHERE EXISTS (
SELECT 1
FROM students
WHERE grade > 4
);
Resultado:
Tem estudantes com nota alta!
Por que EXISTS é mais rápido que IN?
A maior vantagem do EXISTS é que ele para de rodar a subquery assim que acha a primeira correspondência. Ou seja, se você só quer saber se existe algum dado, EXISTS pode ser muito eficiente.
Por exemplo, imagina que a tabela students tem milhões de registros, mas você só quer saber se existe pelo menos um (grade > 4). Assim que o SQL acha a primeira linha que bate, ele já termina a query.
Usando NOT EXISTS
Agora bora falar do NOT EXISTS. Esse operador é tipo o oposto do EXISTS. Ele retorna TRUE se a subquery não retorna nenhum registro.
Exemplo: achar estudantes sem notas (NULL)
Imagina que na nossa tabela tem estudantes que ainda não têm nota:
| id | name | grade |
|---|---|---|
| 1 | Otto | NULL |
| 2 | Anna | 4.7 |
| 3 | Dan | 5.0 |
| 4 | Lina | NULL |
A gente quer pegar todos os estudantes sem nota. Bora usar 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 e IN
Às vezes parece que EXISTS e IN fazem a mesma coisa. De cara — sim, mas tem uns detalhes. Principalmente se tiver um NULL perdido por aí. Aí o IN pode dar um resultado estranho, e o EXISTS salva a pátria.
Bora ver um exemplo.
Tabela courses (cursos que dá pra fazer):
| course_id | name |
|---|---|
| 1 | Matemática |
| 2 | História |
E aqui estão os estudantes:
| student_id | name |
|---|---|
| 1 | Alex Lin |
| 2 | Anna Song |
| 3 | Maria Chi |
| 4 | Dan Seth |
| 5 | Shadow Moon |
Tabela enrollments (quem se inscreveu em qual curso):
| student_id | course_id |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | NULL |
A gente quer pegar os nomes dos cursos que têm alguém inscrito. Parece fácil.
Usando IN:
SELECT name
FROM courses
WHERE course_id IN (
SELECT course_id
FROM enrollments
);
Parece que vai funcionar. Mas se em enrollments tiver NULL no courseid, tipo a Maria Chi, o IN pode não retornar... nada! Porque o NULL deixa a subquery "indefinida", e o SQL fica perdido: vai que NULL é justamente o courseid que a gente procura?
Usando EXISTS:
SELECT name
FROM courses c
WHERE EXISTS (
SELECT 1
FROM enrollments e
WHERE c.course_id = e.course_id
);
Já o EXISTS só pergunta: "Tem pelo menos uma linha onde o course_id bate?" — e pronto. Ele nem liga se tem NULL por perto, porque ele procura correspondência direta, não uma lista de valores.
Resumo: se a subquery pode ter NULL, melhor usar EXISTS pra não ter surpresa.
Exemplos de problemas reais
Tabela students:
| id | name |
|---|---|
| 1 | Alex Lin |
| 2 | Anna Song |
| 3 | Maria Chi |
| 4 | Dan Seth |
| 5 | Shadow Moon |
Tabela enrollments:
| student_id | course_id |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | NULL |
Exemplo 1. Estudantes inscritos em cursos
Bora achar quem já apareceu em algum lugar — se inscreveu em algum curso (mesmo que estranho, tipo a 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
Se o estudante aparece de qualquer jeito em enrollments — ele entra no resultado, mesmo se o course_id dele for estranho.
Exemplo 2. Estudantes sem cursos
Agora bora achar quem só existe no sistema — mas ainda não se inscreveu em 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 esses dois ainda não acharam um curso legal. Ou só esqueceram de se inscrever :)
Exemplo 3. Selecionando cursos com mais de 5 estudantes inscritos
Tabela courses:
| course_id | name |
|---|---|
| 1 | Matemática |
| 2 | História |
| 3 | Biologia |
| 4 | Filosofia |
Tabela 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 |
A gente quer achar os cursos que têm mais de cinco estudantes inscritos. Aqui o EXISTS meio que pergunta: "Esse curso tem pelo menos um grupo de registros com mais de cinco estudantes?"
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ática
Só o curso "Matemática" (course_id = 1) tem seis estudantes inscritos. Os outros ainda não bombaram tanto.
Erros comuns usando EXISTS e NOT EXISTS
- Entender errado a sintaxe da subquery. Sempre confere se a subquery tá referenciando certo a tabela de fora.
- Esquecer de tratar
NULL. Mesmo usandoEXISTS, às vezes você precisa deixar claro como tratar oNULL. - Não ter índice nos campos da subquery. Isso pode deixar a query bem lenta.
É isso por hoje! Agora você já sabe como usar EXISTS e NOT EXISTS pra checar existência de dados, e também as diferenças desses operadores pro IN. Na próxima aula a gente vai continuar mergulhando em subqueries, vendo como usar elas no SELECT pra trabalhar com dados agregados.
GO TO FULL VERSION