EXISTS, IN ou COUNT: qual usar para saber se um registro existe
A pergunta é simples: quais clientes já fizeram algum pedido?
Existem três jeitos comuns de escrever isso. Os três devolvem a resposta certa — mas um deles faz muito mais trabalho do que precisa.
O jeito que quase todo mundo escreve primeiro
SELECT nome
FROM clientes c
WHERE (SELECT COUNT(*) FROM pedidos p WHERE p.id_cliente = c.id) > 0
Funciona. E é o mais caro dos três, por um motivo que salta aos olhos quando você lê em voz alta: você pediu para o banco contar todos os pedidos do cliente só para descobrir se existe pelo menos um.
Se o cliente tem 4 mil pedidos, o banco conta os 4 mil, devolve 4000, e você compara com zero. Os outros 3.999 não mudavam a resposta.
EXISTS: para no primeiro que achar
SELECT nome
FROM clientes c
WHERE EXISTS (
SELECT 1 FROM pedidos p WHERE p.id_cliente = c.id
)
EXISTS responde verdadeiro ou falso. Achou uma linha, já pode parar — a resposta não vai mudar dali em diante.
É por isso que o SELECT 1 lá dentro não é preguiça nem truque: o EXISTS não olha as colunas, só se veio linha. Você poderia escrever SELECT * que dá no mesmo.
IN: a lista de valores
SELECT nome
FROM clientes
WHERE id IN (SELECT id_cliente FROM pedidos)
Se lê muito bem, e na prática os bancos modernos costumam executar isso de forma parecida com o EXISTS — o otimizador reconhece o padrão e para de procurar assim que acha.
O cuidado com o IN é outro: NULL dentro da lista. Se a subquery devolver algum NULL, o NOT IN deixa de funcionar como você espera e passa a não retornar nada. O NOT EXISTS não tem esse problema.
Como escolher
- Só quero saber se existe →
EXISTS - Quero comparar com uma lista curta e conhecida (
IN ('SP','RJ')) →IN - Quero saber quantos → aí sim
COUNT, porque a pergunta mudou
Pra lembrar
COUNT(*) > 0 é a resposta certa para a pergunta errada. Você pediu uma contagem quando queria um sim ou não.
E, na negação, prefira NOT EXISTS a NOT IN: além de não ter a armadilha do NULL, ele diz exatamente o que você quis dizer.