CodeGym /Cursos /SQL SELF /Checando existência de dados com EXISTS e ...

Checando existência de dados com EXISTS e NOT EXISTS

SQL SELF
Nível 13 , Lição 3
Disponível

Seja bem-vindo(a) à nova aula de SQL! Hoje a gente vai conhecer os operadores mais discretos, mas super poderososEXISTS 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 EXISTS pode ser qualquer query.
  • É o resultado da subquery que define se vai voltar TRUE ou FALSE.

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

  1. Entender errado a sintaxe da subquery. Sempre confere se a subquery tá referenciando certo a tabela de fora.
  2. Esquecer de tratar NULL. Mesmo usando EXISTS, às vezes você precisa deixar claro como tratar o NULL.
  3. 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.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION