SQL IS NULL e IS NOT NULL

Na aula O Valor NULL, a Ana descobriu que WHERE email = NULL não acha ninguém: comparar com um valor desconhecido sempre dá "não sei". Mas ela ainda precisa da lista de clientes sem email, e o entregador precisa saber quais pedidos ainda não foram entregues. Para isso o SQL tem duas perguntas especiais, que sempre têm resposta: IS NULL ("está em branco?") e IS NOT NULL ("está preenchido?"). Nesta aula você vai usá-las sozinhas, juntas com outras condições, e vai aprender a fazer o total da tabela fechar.

Você vai aprender
  • coluna IS NULL: as linhas em que a coluna está sem valor.
  • coluna IS NOT NULL: as linhas em que a coluna tem valor.
  • Por que o IS sempre responde 1 ou 0, nunca "não sei".
  • Como juntar IS NULL com AND e OR.
  • Como dividir uma tabela em grupos sem perder ninguém.
  • O IS e o IS DISTINCT FROM: comparar valores tratando NULL como igual a NULL.
  • Os erros mais comuns ao escrever essas condições, com as mensagens reais do SQLite.

Todos os exemplos rodam de verdade, no seu navegador, contra o banco da Loja Aurora. No quadro "Resultado", o NULL aparece como NULL, em itálico.


A ideia: perguntar pelo branco, não pelo valor

Volte ao fichário de papel da loja. Se alguém pergunta "o email do Luís Otávio é igual a ...?", você não tem como responder: o campo está em branco. Mas se a pergunta for "o campo de email do Luís Otávio está em branco?", a resposta é fácil: sim. Essa é a diferença entre = e IS:

PerguntaEm SQLPara o Luís Otávio (email NULL)Para a Fernanda (com email)
"O email é igual a desconhecido?"email = NULLNULL (não sei)NULL (não sei)
"O email está em branco?"email IS NULL1 (sim)0 (não)
"O email está preenchido?"email IS NOT NULL0 (não)1 (sim)

1. IS NULL: quem está sem valor

A lista de clientes sem email, que a Ana queria desde a aula passada:

SELECT id, nome, cidade, email
FROM clientes
WHERE email IS NULL;
WHERE
O filtro de linhas (aula WHERE): só passam as linhas em que a condição é verdadeira.
email
A coluna que você quer examinar.
IS NULL
"É nulo": verdadeiro quando a coluna não tem valor naquela linha. São duas palavras, com espaço no meio, e o NULL vai sem aspas.

Os três clientes: Luís Otávio Brito (7), Roberto Falcão (15) e Henrique Sales (23). Funciona com qualquer coluna. Os clientes sem data de nascimento:

SELECT id, nome, nascimento
FROM clientes
WHERE nascimento IS NULL;

E na tabela de funcionários, quem não tem chefe? Só a gerente, Marta Lustosa:

SELECT id, nome, cargo
FROM funcionarios
WHERE chefe_id IS NULL;

Experimente: o entregador quer a lista de pedidos que ainda não foram entregues (a coluna entregue_em está sem valor). A consulta abaixo usa = NULL e não acha nada. Conserte-a.

SELECT id, data, frete, entregue_em
FROM pedidos
WHERE entregue_em = NULL;
SELECT id, data, frete, entregue_em
FROM pedidos
WHERE entregue_em IS NULL;

2. IS NOT NULL: quem tem valor

O contrário: as linhas em que a coluna está preenchida. O gerente quer ver os pedidos de agosto de 2026 em diante que já foram entregues:

SELECT id, data, entregue_em
FROM pedidos
WHERE entregue_em IS NOT NULL
  AND data >= '2026-08-01';
IS NOT NULL
"Não é nulo": verdadeiro quando a coluna tem um valor, seja ele qual for (até um 0 ou um texto vazio '' contam como valor).
AND data >= '2026-08-01'
Uma segunda condição, ligada com AND (aula AND): o pedido precisa ter sido entregue e ser de agosto de 2026 em diante.

Quatro pedidos, do 82 ao 85. Os pedidos de 86 a 90 também são desse período, mas ainda não chegaram, e o IS NOT NULL os deixou de fora. Atenção à ordem das palavras: é IS NOT NULL, com o NOT no meio.

Também dá para escrever o mesmo com NOT na frente da condição inteira (aula NOT). O resultado é idêntico, mas o IS NOT NULL é mais fácil de ler:

SELECT id, data, entregue_em
FROM pedidos
WHERE NOT (entregue_em IS NULL)
  AND data >= '2026-08-01';

3. O IS sempre responde

Essa é a grande diferença para o =. Teste com valores soltos:

SELECT NULL IS NULL, '' IS NULL, 0 IS NULL, 'NULL' IS NULL, NULL IS NOT NULL;
  1. NULL IS NULL → 1: sim, está em branco.
  2. '' IS NULL → 0: o texto vazio é um valor; não está em branco.
  3. 0 IS NULL → 0: zero também é um valor.
  4. 'NULL' IS NULL → 0: entre aspas, 'NULL' é uma palavra comum.
  5. NULL IS NOT NULL → 0: um branco não está preenchido.

Nenhuma resposta é NULL. Por isso o IS NULL funciona no WHERE: a pergunta "está em branco?" sempre tem um sim ou um não.


4. Juntando com AND e OR

A Ana vai ligar para completar o cadastro de quem está com email ou data de nascimento faltando:

SELECT id, nome, email, nascimento
FROM clientes
WHERE email IS NULL OR nascimento IS NULL;

Cinco clientes: os três sem email (7, 15, 23) e os dois sem nascimento (9, 21). Cada IS NULL é uma condição completa, com o nome da coluna antes. E se ela trocar o OR por AND?

SELECT id, nome, email, nascimento
FROM clientes
WHERE email IS NULL AND nascimento IS NULL;

Nenhum. Com AND, o cliente precisaria estar sem email e sem nascimento ao mesmo tempo, e ninguém na Aurora está assim. A escolha entre AND e OR é a mesma das aulas AND e OR: o IS NULL é só mais uma condição.

Com outras condições também. Quais pedidos não entregues têm frete acima de R$ 10?

SELECT id, cliente_id, data, frete
FROM pedidos
WHERE entregue_em IS NULL AND frete > 10;

5. O total que fecha

Na aula passada, os fornecedores "do Piauí" (2) mais os "de fora do Piauí" (2) davam 4, e a Aurora tem 6. Faltavam os estrangeiros, com estado NULL. Agora você sabe pedir esse terceiro grupo:

SELECT nome, estado, pais
FROM fornecedores
WHERE estado IS NULL;

Com os três grupos, o total fecha: 2 + 2 + 2 = 6.

GrupoCondiçãoFornecedores
No Piauíestado = 'PI'2 (ids 1 e 6)
Em outro estadoestado <> 'PI'2 (ids 2 e 3)
Sem estado (estrangeiros)estado IS NULL2 (ids 4 e 5)

Para "todo mundo que não é do Piauí, inclusive quem não tem estado", junte os dois últimos com OR:

SELECT nome, estado, pais
FROM fornecedores
WHERE estado <> 'PI' OR estado IS NULL;
Um hábito que evita surpresas

Antes de escrever um <>, um NOT ou um NOT BETWEEN, pergunte: "essa coluna pode ter NULL?". Se pode, decida o que fazer com essas linhas e escreva isso no SQL (OR coluna IS NULL para incluir, AND coluna IS NOT NULL para deixar claro que ficam de fora). O .schema do terminal (aula Comandos de Ponto) mostra quais colunas são NOT NULL, e essas nunca têm branco.


6. O IS do SQLite e o IS DISTINCT FROM

Às vezes você quer comparar dois valores e tratar o branco como um valor normal: "o estado é diferente de PI, contando o branco como diferente". O SQL padrão tem para isso o IS DISTINCT FROM ("é diferente de", tratando NULL como um valor), e o SQLite entende:

SELECT nome, estado
FROM fornecedores
WHERE estado IS DISTINCT FROM 'PI';

Os quatro de fora do Piauí, com os estrangeiros incluídos, numa condição só. O contrário é IS NOT DISTINCT FROM ("é igual a, tratando NULL como igual a NULL"). No SQLite, o próprio IS e o IS NOT funcionam assim, com qualquer valor, não só com NULL:

SELECT nome, estado
FROM fornecedores
WHERE estado IS NOT 'PI';

Compare as quatro formas de perguntar "são iguais?":

SELECT NULL = NULL,
       NULL IS NULL,
       NULL IS NOT DISTINCT FROM NULL,
       1 IS DISTINCT FROM NULL;
FormaCom NULLOnde funciona
a = bDá NULLTodo banco
a IS NULL1 ou 0Todo banco (SQL padrão)
a IS NOT DISTINCT FROM b1 ou 0 (NULL igual a NULL)SQL padrão; SQLite e PostgreSQL
a IS b com b diferente de NULL1 ou 0Do SQLite; não conte com ele em outros bancos

Para o dia a dia, guarde o IS NULL e o IS NOT NULL: eles funcionam em qualquer banco e todo mundo entende.

Atalhos que só o SQLite aceita

O SQLite também entende email ISNULL, email NOTNULL e até email NOT NULL (sem o IS) no WHERE. Você pode encontrá-los em código antigo, mas não os use: o primeiro e o segundo não são do SQL padrão, e o terceiro se confunde com a restrição NOT NULL do CREATE TABLE (aula NOT NULL). Escreva sempre IS NULL e IS NOT NULL.


Formas diferentes de achar os brancos

A mesma pergunta, "fornecedores de fora do Piauí, inclusive os estrangeiros", de quatro jeitos que dão o mesmo resultado (4 linhas):

FormaQuando usar
WHERE estado <> 'PI' OR estado IS NULLA mais clara e portátil: diz com todas as letras o que fazer com o branco. Use esta.
WHERE estado IS DISTINCT FROM 'PI'Mais curta, do SQL padrão; funciona no SQLite e no PostgreSQL.
WHERE estado IS NOT 'PI'Só no SQLite.
WHERE estado <> 'PI' OR pais <> 'Brasil'Usa outra coluna sem NULL; funciona aqui porque sabemos que os estrangeiros são exatamente os sem estado.

Quando dá errado

Usou = NULL (ou == NULL)
SELECT nome
FROM clientes
WHERE email == NULL;

O que acontece: zero linhas, sem erro. O SQLite aceita == como sinônimo de =, e os dois comparam valores: com NULL, a resposta é sempre "não sei".

Como consertar: WHERE email IS NULL.

Escreveu NOT IS em vez de IS NOT
SELECT nome
FROM clientes
WHERE email NOT IS NULL;

A mensagem: near "IS": syntax error ("perto de IS: erro de sintaxe"). Depois de email NOT, o SQLite esperava coisas como LIKE, IN ou BETWEEN (email NOT LIKE …), e não um IS.

Como consertar: o NOT vai no meio: email IS NOT NULL.

Esqueceu o IS
SELECT nome
FROM clientes
WHERE email NULL;

A mensagem: near "NULL": syntax error. Uma coluna seguida direto de NULL não é uma condição.

Como consertar: WHERE email IS NULL.

Errou a palavra NULL
SELECT nome
FROM clientes
WHERE email IS NUL;

A mensagem: no such column: NUL ("não existe a coluna NUL"). Uma palavra que não é do SQL vira, para o SQLite, o nome de uma coluna, e a tabela não tem essa coluna. O mesmo acontece com IS EMPTY (no such column: EMPTY): "vazio" não existe em SQL; o branco é NULL.

Como consertar: IS NULL, com dois L.

Pôs o NULL entre aspas
SELECT nome
FROM clientes
WHERE email IS 'NULL';

O que acontece: zero linhas, sem erro. Com aspas, 'NULL' é uma palavra de quatro letras, e o IS do SQLite compara o email com essa palavra. Nenhum email é "NULL".

Como consertar: sem aspas: IS NULL.

Usou a função ISNULL() de outro banco
SELECT nome
FROM clientes
WHERE ISNULL(email);

A mensagem: near "ISNULL": syntax error. No MySQL, ISNULL(expr) é uma função que testa se o valor é NULL; no SQL Server, ISNULL(valor, substituto) faz outra coisa, troca o NULL por um valor. No SQLite, ISNULL só existe depois da coluna (email ISNULL), e não como função.

Como consertar: WHERE email IS NULL, que funciona nos três.

Nos outros bancos
  • IS NULL e IS NOT NULL são do SQL padrão e funcionam igual no MySQL, no PostgreSQL e no SQL Server.
  • PostgreSQL: tem IS DISTINCT FROM e IS NOT DISTINCT FROM como o SQLite. Também aceita ISNULL e NOTNULL depois da expressão, mas o manual os chama de "não padrão".
  • MySQL: a igualdade que trata NULL como igual a NULL é o operador <=>; o manual diz que ele equivale ao IS NOT DISTINCT FROM do padrão. Trecho só ilustrativo:
    SELECT 1 <=> 1, NULL <=> NULL, 1 <=> NULL;
    -- 1, 1, 0
    
  • SQL Server: a documentação da função ISNULL avisa: "não use ISNULL para achar valores NULL; use IS NULL".

Referência rápida

EscritaO que faz
x IS NULL1 se x está sem valor, 0 se tem valor
x IS NOT NULL1 se x tem valor (inclusive 0 e '')
NOT (x IS NULL)O mesmo que x IS NOT NULL
x <> v OR x IS NULLDiferente de v, contando os brancos
x IS DISTINCT FROM vDiferente, tratando NULL como valor (padrão; SQLite, PostgreSQL)
x IS NOT DISTINCT FROM vIgual, tratando NULL como igual a NULL
x IS v, x IS NOT vO mesmo, no jeito curto do SQLite
Mensagem ou sintomaQuer dizer
0 linhas, sem erroUsou = NULL, == NULL ou 'NULL' entre aspas
near "IS": syntax errorEscreveu NOT IS; o certo é IS NOT
near "NULL": syntax errorFaltou o IS
no such column: NULPalavra errada: o certo é NULL
near "ISNULL": syntax errorISNULL() como função não existe no SQLite

Exercícios

1. Os clientes sem email

SELECT nome FROM clientes WHERE email ;

2. Os pedidos já entregues

SELECT id FROM pedidos WHERE entregue_em IS NULL;

3. Quanto dá SELECT '' IS NULL;?

4. Qual destas condições está escrita do jeito certo e funciona em qualquer banco?

5. Na Aurora, ninguém está sem email e sem nascimento ao mesmo tempo. Quantas linhas WHERE email IS NULL AND nascimento IS NULL devolve?

Missão: o gerente quer os pedidos de agosto de 2026 em diante que já foram entregues. A consulta abaixo traz todos os pedidos do período, inclusive os que ainda estão a caminho. Acrescente a condição que falta.

SELECT id, data, entregue_em
FROM pedidos
WHERE data >= '2026-08-01';
SELECT id, data, entregue_em
FROM pedidos
WHERE data >= '2026-08-01'
  AND entregue_em IS NOT NULL;

Missão final: o cadastro incompleto

Missão: a Ana vai ligar para todos os clientes com cadastro incompleto: quem está sem email ou sem data de nascimento. A consulta abaixo só olha o email. Complete a condição para trazer os 5 clientes.

SELECT id, nome, email, nascimento
FROM clientes
WHERE email IS NULL;
SELECT id, nome, email, nascimento
FROM clientes
WHERE email IS NULL OR nascimento IS NULL;

Se você usou AND no lugar do OR, viu zero linhas: releia a seção 4.


Resumo

  • coluna IS NULL acha as linhas em que a coluna está sem valor; coluna IS NOT NULL, as que têm valor.
  • O IS sempre responde 1 ou 0, nunca "não sei". Por isso funciona no WHERE, e o = NULL não.
  • 0, '' e 'NULL' são valores: para eles, IS NULL dá 0.
  • IS NULL é uma condição como outra qualquer: combine com AND e OR, com o nome da coluna em cada uma.
  • Para o total fechar, conte o terceiro grupo: = v, <> v e IS NULL. Para "diferente, incluindo os brancos": x <> v OR x IS NULL.
  • IS DISTINCT FROM (padrão) e o IS do SQLite comparam tratando NULL como valor. No dia a dia, prefira IS NULL e IS NOT NULL.
  • É IS NOT NULL, nunca NOT IS NULL (near "IS": syntax error).