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.
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
ISsempre responde 1 ou 0, nunca "não sei". - Como juntar
IS NULLcomANDeOR. - Como dividir uma tabela em grupos sem perder ninguém.
- O
ISe oIS DISTINCT FROM: comparar valores tratandoNULLcomo igual aNULL. - 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:
| Pergunta | Em SQL | Para o Luís Otávio (email NULL) | Para a Fernanda (com email) |
|---|---|---|---|
| "O email é igual a desconhecido?" | email = NULL | NULL (não sei) | NULL (não sei) |
| "O email está em branco?" | email IS NULL | 1 (sim) | 0 (não) |
| "O email está preenchido?" | email IS NOT NULL | 0 (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.
- 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
NULLvai 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
0ou 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;
NULL IS NULL→1: sim, está em branco.'' IS NULL→0: o texto vazio é um valor; não está em branco.0 IS NULL→0: zero também é um valor.'NULL' IS NULL→0: entre aspas,'NULL'é uma palavra comum.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.
| Grupo | Condição | Fornecedores |
|---|---|---|
| No Piauí | estado = 'PI' | 2 (ids 1 e 6) |
| Em outro estado | estado <> 'PI' | 2 (ids 2 e 3) |
| Sem estado (estrangeiros) | estado IS NULL | 2 (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;
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;
| Forma | Com NULL | Onde funciona |
|---|---|---|
a = b | Dá NULL | Todo banco |
a IS NULL | 1 ou 0 | Todo banco (SQL padrão) |
a IS NOT DISTINCT FROM b | 1 ou 0 (NULL igual a NULL) | SQL padrão; SQLite e PostgreSQL |
a IS b com b diferente de NULL | 1 ou 0 | Do 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.
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):
| Forma | Quando usar |
|---|---|
WHERE estado <> 'PI' OR estado IS NULL | A 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
= 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.
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.
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.
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.
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.
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.
IS NULLeIS NOT NULLsão do SQL padrão e funcionam igual no MySQL, no PostgreSQL e no SQL Server.- PostgreSQL: tem
IS DISTINCT FROMeIS NOT DISTINCT FROMcomo o SQLite. Também aceitaISNULLeNOTNULLdepois da expressão, mas o manual os chama de "não padrão". - MySQL: a igualdade que trata
NULLcomo igual aNULLé o operador<=>; o manual diz que ele equivale aoIS NOT DISTINCT FROMdo padrão. Trecho só ilustrativo:SELECT 1 <=> 1, NULL <=> NULL, 1 <=> NULL; -- 1, 1, 0
- SQL Server: a documentação da função
ISNULLavisa: "não useISNULLpara achar valoresNULL; useIS NULL".
Referência rápida
| Escrita | O que faz |
|---|---|
x IS NULL | 1 se x está sem valor, 0 se tem valor |
x IS NOT NULL | 1 se x tem valor (inclusive 0 e '') |
NOT (x IS NULL) | O mesmo que x IS NOT NULL |
x <> v OR x IS NULL | Diferente de v, contando os brancos |
x IS DISTINCT FROM v | Diferente, tratando NULL como valor (padrão; SQLite, PostgreSQL) |
x IS NOT DISTINCT FROM v | Igual, tratando NULL como igual a NULL |
x IS v, x IS NOT v | O mesmo, no jeito curto do SQLite |
| Mensagem ou sintoma | Quer dizer |
|---|---|
| 0 linhas, sem erro | Usou = NULL, == NULL ou 'NULL' entre aspas |
near "IS": syntax error | Escreveu NOT IS; o certo é IS NOT |
near "NULL": syntax error | Faltou o IS |
no such column: NUL | Palavra errada: o certo é NULL |
near "ISNULL": syntax error | ISNULL() como função não existe no SQLite |
Exercícios
1. Os clientes sem email
2. Os pedidos já entregues
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 NULLacha as linhas em que a coluna está sem valor;coluna IS NOT NULL, as que têm valor.- O
ISsempre responde 1 ou 0, nunca "não sei". Por isso funciona noWHERE, e o= NULLnão. 0,''e'NULL'são valores: para eles,IS NULLdá 0.IS NULLé uma condição como outra qualquer: combine comANDeOR, com o nome da coluna em cada uma.- Para o total fechar, conte o terceiro grupo:
= v,<> veIS NULL. Para "diferente, incluindo os brancos":x <> v OR x IS NULL. IS DISTINCT FROM(padrão) e oISdo SQLite comparam tratandoNULLcomo valor. No dia a dia, prefiraIS NULLeIS NOT NULL.- É
IS NOT NULL, nuncaNOT IS NULL(near "IS": syntax error).