Voltar para o conteúdo

Dica rápida: NOT IN com NULL pode zerar seu resultado em SQL

Entenda por que um único NULL dentro da subquery faz o filtro com NOT IN sumir com linhas válidas e qual troca resolve isso sem drama.

Raphael Carvalho · 08 de jun. de 2026 · 5 min de leitura

Resumo rápido

  • Se a subquery de um NOT IN devolver pelo menos um NULL, a comparação inteira pode deixar de retornar linhas válidas.
  • O sinal verde é simples: filtrar NULL na subquery ou trocar a lógica para NOT EXISTS quando a intenção for anti-join.
  • Esse erro aparece em exclusões de clientes, pedidos ou eventos e costuma mascarar problemas de qualidade de dados.

Seção: Dicas Rápidas

Tem um erro que parece pequeno, mas derruba muita análise silenciosamente: usar NOT IN contra uma subquery que devolve pelo menos um NULL.

Na prática, o efeito é frustrante. Você espera listar clientes sem pedido, produtos sem venda ou eventos que não passaram por uma etapa do funil. A query roda, não quebra, mas devolve menos linhas do que deveria, ou até zero. Quem olha rápido acha que o problema está no negócio. Muitas vezes ele está na semântica do NULL.

O erro em 20 segundos

Imagine esta consulta:

SELECT c.id_cliente, c.nome
FROM clientes c
WHERE c.id_cliente NOT IN (
  SELECT p.id_cliente
  FROM pedidos p
  WHERE p.status = 'cancelado'
);

Se pedidos.id_cliente tiver um único NULL entre os cancelados, o filtro pode parar de funcionar como você imagina. O banco não consegue afirmar com segurança que c.id_cliente não está na lista, porque a lista contém um valor desconhecido.

Resultado: linhas legítimas ficam de fora.

O que validar antes de confiar na saída

Antes de usar NOT IN, cheque duas coisas:

  1. A coluna retornada pela subquery pode vir com NULL?
  2. A sua intenção real é excluir valores de uma lista ou fazer um anti-join entre tabelas?

Esse passo leva menos de um minuto e evita um monte de conclusão errada em dashboard, análise ad hoc e query de produção.

Sinal verde

O sinal verde aparece quando a subquery garante um conjunto sem NULL ou quando você explicita isso no filtro:

SELECT c.id_cliente, c.nome
FROM clientes c
WHERE c.id_cliente NOT IN (
  SELECT p.id_cliente
  FROM pedidos p
  WHERE p.status = 'cancelado'
    AND p.id_cliente IS NOT NULL
);

Aqui a intenção fica coerente: você está comparando ids conhecidos contra ids conhecidos.

Erro comum

O erro mais comum é assumir que NOT IN é sempre o oposto direto de IN. Em SQL, NULL quebra essa intuição porque ele representa valor desconhecido, não vazio e não zero.

Quando a subquery pode retornar NULL, a comparação deixa de ser binária. Não é mais apenas “está na lista” ou “não está na lista”. Passa a existir o terceiro estado: “não sei”. E filtro com resultado desconhecido não entra no WHERE.

Isso costuma aparecer em cenários como:

  • chaves estrangeiras opcionais;
  • tabelas de eventos com preenchimento inconsistente;
  • uniões temporárias feitas sem saneamento;
  • dados históricos legados.

Ação rápida

Se o objetivo for anti-join, a troca mais segura costuma ser NOT EXISTS:

SELECT c.id_cliente, c.nome
FROM clientes c
WHERE NOT EXISTS (
  SELECT 1
  FROM pedidos p
  WHERE p.status = 'cancelado'
    AND p.id_cliente = c.id_cliente
);

Essa versão tende a ser mais legível para o caso de negócio e não cai na mesma armadilha do NULL na lista retornada.

Quando usar cada abordagem

Use NOT IN quando você realmente tem uma lista limpa e controlada de valores.

Use NOT EXISTS quando:

  • a comparação depende de relacionamento entre tabelas;
  • a origem pode trazer NULL;
  • a query precisa comunicar claramente que você quer ausência de correspondência.

Não é questão de dogma. É questão de reduzir surpresa operacional.

Leitura prática para analista

Esse tipo de detalhe separa query que “roda” de query que sustenta decisão. Em ambiente real, o maior risco não é um erro de sintaxe. É um resultado aparentemente plausível que passa batido para quem está olhando só o número final.

Se você trabalha com exclusões, reconciliação de bases, segmentos de CRM ou funis operacionais, vale transformar isso em checklist:

  • validar NULL na subquery;
  • decidir entre NOT IN e NOT EXISTS;
  • comparar a contagem antes e depois da troca;
  • documentar a escolha se a query vai virar ativo recorrente.

Resumo direto

NOT IN com NULL é uma armadilha clássica porque não explode a query. Ele só corrói a confiança na saída.

Quando houver qualquer chance de NULL aparecer na subquery, filtre esse valor explicitamente ou prefira NOT EXISTS. É um ajuste pequeno, mas evita muito falso negativo em análise SQL.

SQL do Zero ao Avançado

Pratique SQL no navegador com aulas, exercícios reais e editor ao vivo.

Conhecer o curso de SQL

Perguntas frequentes

Por que o NOT IN falha quando existe NULL?

Porque a comparação vira indeterminada para o otimizador SQL. Em vez de afirmar que o valor não está na lista, o banco trata a expressão como desconhecida e a linha não passa no filtro.

Quando devo preferir NOT EXISTS?

Quando você quer excluir linhas com base em correspondência entre tabelas. NOT EXISTS costuma ser mais explícito para anti-join e evita a armadilha do NULL na lista retornada.

Curso em português para brasileiros

SQL do Zero ao Avançado

A plataforma interativa de SQL feita para analistas. Pare de depender da fila de engenharia de dados.

Conheça o curso

Advertisement: SQL do Zero ao Avançado

Sobre o autor

Raphael Carvalho

Founder & Principal Consultant

Compartilhar Twitter LinkedIn

Leituras recomendadas