SQL O Valor NULL

Quando a Ana cadastrou o cliente Luís Otávio Brito na Loja Aurora, ele não quis dar o email. O campo ficou sem nada. No banco, esse "nada" tem nome: NULL (em inglês, "nulo"). Ele parece simples, mas é a fonte de muitos dos resultados estranhos que você vai encontrar em SQL: consultas que voltam vazias sem erro, totais que não fecham, contas que somem. Nesta aula você vai entender o que o NULL é, por que email = NULL nunca funciona e como o SQL pensa com três respostas possíveis: verdadeiro, falso e "não sei".

Você vai aprender
  • O que é o NULL: um valor desconhecido ou que não existe.
  • Por que NULL não é zero, nem texto vazio, nem a palavra 'NULL'.
  • Onde o NULL aparece na Loja Aurora, no editor e no terminal do sqlite3.
  • Por que WHERE email = NULL devolve zero linhas, sem dar erro.
  • A lógica de três valores: como AND, OR e NOT se comportam com o "não sei".
  • O que acontece com o NULL numa conta, numa ordenação e num DISTINCT.

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


A ideia: a ficha com um campo em branco

Imagine o fichário de clientes da loja, em papel. Na ficha do Luís Otávio, a linha "email" ficou em branco. O que esse branco quer dizer?

  • Talvez ele não tenha email.
  • Talvez tenha, mas não quis informar.
  • Talvez a Ana tenha esquecido de perguntar.

Você não sabe. É isso que o NULL representa: "aqui não tem valor; o valor é desconhecido". Repare que um branco é muito diferente de uma ficha em que está escrito "não tem email", ou de um campo "filhos" preenchido com 0. Zero é uma informação (a pessoa não tem filhos); o branco é a falta de informação.

Na ficha de papelNo bancoQuer dizer
Campo em brancoNULLNão sabemos / não existe
"0" escrito no campo0Sabemos, e é zero
Um traço "—" ou um campo apagado de propósito'' (texto vazio)Sabemos, e é um texto sem letras
Alguém escreveu a palavra "NULL"'NULL'Um texto comum, de quatro letras

1. Onde o NULL aparece na Loja Aurora

O banco da Aurora tem vários campos sem valor, de propósito. Os clientes de número 6 a 8:

SELECT id, nome, email
FROM clientes
WHERE id BETWEEN 6 AND 8;

O cliente 7, Luís Otávio Brito, aparece com NULL no email. Ele não é o único. Estes são os "brancos" da Aurora:

Tabela e colunaQuem tem NULLPor quê
clientes.emailClientes 7, 15 e 23Não deram email
clientes.nascimentoClientes 9 e 21Data de nascimento não informada
fornecedores.estadoFornecedores 4 (Portugal) e 5 (Argentina)Não existe "estado brasileiro" fora do Brasil
pedidos.entregue_emPedidos 86 a 90Ainda não foram entregues
funcionarios.chefe_idFuncionária 1, a gerenteEla não tem chefe

Repare que o NULL pode querer dizer coisas diferentes: "ninguém informou" (o email), "ainda não aconteceu" (a entrega) ou "não se aplica" (o estado de um fornecedor estrangeiro). Para o SQL, é sempre o mesmo NULL. Veja os pedidos mais recentes:

SELECT id, data, entregue_em
FROM pedidos
WHERE id >= 84;

No terminal, o NULL aparece em branco

No programa sqlite3 (aula O Terminal do SQLite), o NULL sai como nada: o email do cliente 7 simplesmente some depois da barra. Para enxergar, o comando de ponto .nullvalue escolhe um texto para mostrar no lugar:

$ sqlite3 loja.db
SQLite version 3.50.4 2025-07-30 19:33:53
Enter ".help" for usage hints.
sqlite> SELECT id, nome, email FROM clientes WHERE id BETWEEN 6 AND 8;
6|Rafael Monteiro|rafael.monteiro@exemplo.com.br
7|Luís Otávio Brito|          « o NULL: nada depois da barra
8|Fernanda Carvalho|fernanda.carvalho@exemplo.com.br
sqlite> .nullvalue NULL
sqlite> SELECT id, nome, email FROM clientes WHERE id BETWEEN 6 AND 8;
6|Rafael Monteiro|rafael.monteiro@exemplo.com.br
7|Luís Otávio Brito|NULL
8|Fernanda Carvalho|fernanda.carvalho@exemplo.com.br
sqlite> .quit

O .nullvalue só muda o que o terminal mostra; o dado continua sendo NULL. Ele vale até você fechar o sqlite3. No editor do guia não é preciso: o quadro já escreve NULL em itálico.


2. NULL não é zero, nem vazio, nem a palavra "NULL"

A função typeof() do SQLite diz de que tipo é um valor. Compare:

SELECT typeof(NULL), typeof(''), typeof(0), typeof('NULL');
typeof(NULL) → null
O NULL é um tipo à parte: não é número nem texto.
typeof('') → text
Duas aspas simples sem nada no meio são um texto vazio: um valor conhecido, com zero letras.
typeof(0) → integer
Zero é um número inteiro como outro qualquer.
typeof('NULL') → text
Entre aspas, 'NULL' é só uma palavra de quatro letras. Nada a ver com o valor NULL.

A diferença aparece nas funções também. length() conta as letras de um texto:

SELECT length(''), length(NULL);

O texto vazio tem 0 letras. O NULL tem... não se sabe: a resposta é NULL. Guarde essa ideia, porque ela é a regra geral: quase tudo o que toca num NULL vira NULL.


3. Por que = NULL não funciona

A Ana quer a lista de clientes sem email, para pedir o contato na próxima compra. O jeito "óbvio" é este:

SELECT nome, email
FROM clientes
WHERE email = NULL;

Zero linhas, e nenhuma mensagem de erro. Mas você acabou de ver que o cliente 7 tem email NULL! E o contrário também falha:

SELECT nome, email
FROM clientes
WHERE email <> NULL;

Também zero, embora 27 clientes tenham email. Para entender, pergunte em português: "o email do Luís Otávio é igual a um valor desconhecido?". A resposta honesta é "não sei". E o email da Fernanda, que é conhecido, é igual a um valor desconhecido? Também "não sei". Comparar qualquer coisa com NULL dá NULL, o "não sei" do SQL:

SELECT NULL = NULL, 1 = NULL, NULL <> NULL, NULL > 5, NULL = 0, NULL = '';

Todas as seis respostas são NULL, inclusive NULL = NULL. Pense em duas fichas com o email em branco: os dois emails são iguais? Ninguém sabe; podem ser iguais ou diferentes. E o WHERE tem uma regra só: ele deixa passar apenas as linhas em que a condição é verdadeira. "Falso" não passa, e "não sei" também não passa. Por isso WHERE email = NULL nunca encontra nada, em nenhum banco.

Então como se procura um NULL?

Com um operador feito para isso: IS NULL ("é nulo"). Ele não compara valores; ele pergunta "este campo está em branco?", e essa pergunta sempre tem resposta. É o assunto da próxima aula, IS NULL e IS NOT NULL. Só para matar a curiosidade:

SELECT nome, email
FROM clientes
WHERE email IS NULL;

4. A lógica de três valores

Até aqui, nas aulas de AND, OR e NOT, toda condição era verdadeira (1) ou falsa (0). Com o NULL, o SQL ganha um terceiro valor: desconhecido. Por isso se diz que o SQL usa uma lógica de três valores.

Como o AND, o OR e o NOT lidam com o "não sei"? Veja de verdade:

SELECT NULL AND 0, NULL AND 1, NULL OR 1, NULL OR 0, NOT NULL;

Parece estranho, mas tem lógica. Pense que o NULL é uma carta virada para baixo, que pode ser verdadeira ou falsa:

  1. NULL AND 0 → 0. O AND precisa que os dois lados sejam verdadeiros. Um lado já é falso, então não importa a carta virada: o resultado é falso.
  2. NULL AND 1 → NULL. Um lado é verdadeiro; o resultado depende da carta virada. Não sei.
  3. NULL OR 1 → 1. O OR precisa de um lado verdadeiro. Já tem um, então é verdadeiro, seja qual for a carta.
  4. NULL OR 0 → NULL. Um lado é falso; tudo depende da carta virada. Não sei.
  5. NOT NULL → NULL. O contrário de "não sei" continua sendo "não sei".

As tabelas completas (V = verdadeiro, F = falso, ? = desconhecido, o NULL):

aba AND ba OR b
VVVV
VFFV
V??V
FFFF
F?F?
????
aNOT a
VF
FV
??

Experimente: antes de rodar, tente adivinhar cada resposta. Depois, troque o SQL para mostrar, nesta ordem, três colunas: NULL OR 1, NULL AND 0 e NULL = NULL. Confira se o resultado é verdadeiro, falso e desconhecido.

SELECT NULL OR 0, NULL AND 1, NULL = 1;
SELECT NULL OR 1, NULL AND 0, NULL = NULL;

5. O total que não fecha

A consequência mais traiçoeira do "não sei" aparece quando você divide a tabela em dois grupos. A Aurora tem 6 fornecedores. Os que ficam no Piauí:

SELECT nome, estado
FROM fornecedores
WHERE estado = 'PI';

E os que não ficam no Piauí:

SELECT nome, estado
FROM fornecedores
WHERE estado <> 'PI';

Dois mais dois dá quatro. Cadê os outros dois fornecedores? São a Lusitana Comércio (Portugal) e a Pampa Sur (Argentina), com estado NULL. Para eles, tanto estado = 'PI' quanto estado <> 'PI' dão "não sei", e o WHERE barra os dois. Eles somem dos dois lados.

O mesmo acontece com os clientes: WHERE email LIKE '%@exemplo.com.br' traz 27, e WHERE email NOT LIKE '%@exemplo.com.br' traz 0. Faltam 3. Você já viu isso com o BETWEEN e o NOT BETWEEN, na aula BETWEEN. A regra é sempre a mesma: se a coluna pode ter NULL, "sim" + "não" pode não dar o total.

SELECT nome, email
FROM clientes
WHERE email NOT LIKE '%@exemplo.com.br';

6. NULL em contas e em textos

A Ana quer montar o contato dos clientes no formato Nome <email>. Em SQL, || junta textos (aula Funções de Texto):

SELECT nome, email,
       nome || ' <' || email || '>' AS contato
FROM clientes
WHERE id BETWEEN 6 AND 8;

Para o cliente 7, o contato inteiro virou NULL, e o nome dele, que é conhecido, sumiu junto. Juntar um texto com "não sei" dá "não sei". Com números é igual:

SELECT 10 + NULL, NULL * 0;

Até NULL * 0 dá NULL: o SQL não tenta ser esperto; qualquer conta com um valor desconhecido tem resultado desconhecido. Para trocar o NULL por um valor padrão antes da conta (por exemplo, "sem email"), existem as funções IFNULL e COALESCE, que têm aula própria: IFNULL e COALESCE.


7. NULL na ordenação e no DISTINCT

Se o NULL não é igual a nada, onde ele fica num ORDER BY? No SQLite, os NULL vêm primeiro na ordem crescente, como se fossem menores que qualquer valor:

SELECT nome, nascimento
FROM clientes
ORDER BY nascimento
LIMIT 4;

Antônio e Sebastião, sem data, aparecem antes da cliente mais velha. Com DESC, eles vão para o fim. Se quiser os NULL no fim mesmo em ordem crescente, o SQLite aceita NULLS LAST:

SELECT nome, nascimento
FROM clientes
ORDER BY nascimento NULLS LAST
LIMIT 3;

E no DISTINCT (aula SELECT DISTINCT), os NULL são tratados como um grupo só: os dois fornecedores estrangeiros viram uma linha NULL:

SELECT DISTINCT estado
FROM fornecedores;

Aqui o SQL faz uma exceção à regra do "não sei": para agrupar e ordenar, todos os NULL ficam juntos.


Formas diferentes de lidar com um campo sem valor

Você querEscrevaNão escreva
Achar quem não tem emailWHERE email IS NULL (próxima aula)WHERE email = NULL (sempre 0 linhas)
Achar quem tem emailWHERE email IS NOT NULLWHERE email <> NULL (sempre 0 linhas)
Dividir a tabela em "sim" e "não" sem perder ninguémPense no terceiro grupo: ... OR estado IS NULLSó estado = 'PI' e estado <> 'PI'
Mostrar um texto no lugar do brancoIFNULL(email, 'sem email') (aula IFNULL e COALESCE)email || '' (continua NULL)
Ver o NULL no terminal.nullvalue NULLProcurar o texto 'NULL' com WHERE email = 'NULL'
Guardar "não tem" como informaçãoDecida e documente: NULL = desconhecido; 0 ou '' = sabidoMisturar os dois na mesma coluna

Quando dá errado

O NULL quase nunca dá mensagem de erro. Ele dá resultado errado, o que é pior. Em cada caso, o quadro mostra o que o SQLite fez de verdade.

Procurou com = NULL
SELECT id, data
FROM pedidos
WHERE entregue_em = NULL;

O que acontece: zero linhas, embora 5 pedidos (86 a 90) não tenham sido entregues. entregue_em = NULL é sempre "não sei", e o WHERE barra tudo.

Como consertar: WHERE entregue_em IS NULL (aula IS NULL e IS NOT NULL).

Procurou a palavra 'NULL'
SELECT nome
FROM clientes
WHERE email = 'NULL';

O que acontece: zero linhas. Entre aspas, 'NULL' é um texto de quatro letras, e nenhum cliente tem esse texto como email. É comum cair nisso depois de ver "NULL" escrito no resultado ou no terminal: aquilo é só o jeito de mostrar o branco.

Como consertar: sem aspas, e com IS: WHERE email IS NULL.

Um NULL dentro do NOT IN
SELECT id, nome
FROM clientes
WHERE id NOT IN (1, 2, NULL);

O que acontece: zero linhas! A Ana queria todos os clientes menos o 1 e o 2. Mas id NOT IN (1, 2, NULL) é o mesmo que id <> 1 AND id <> 2 AND id <> NULL, e esse último pedaço é sempre "não sei". Pela tabela do AND, "verdadeiro AND não sei" dá "não sei". Nenhuma linha passa. (O IN sem o NOT funciona: id IN (1, 2, NULL) traz os clientes 1 e 2, porque "verdadeiro OR não sei" é verdadeiro.) Esse caso é raro numa lista digitada à mão, mas aparece de verdade quando a lista vem de uma subconsulta que devolve algum NULL.

Como consertar: nunca deixe NULL numa lista de NOT IN: WHERE id NOT IN (1, 2).

Tentou apagar um dado obrigatório

Nem toda coluna aceita NULL. Quem criou a tabela pode exigir um valor com NOT NULL (aula NOT NULL). Na Aurora, o nome do cliente é obrigatório:

UPDATE clientes
SET nome = NULL
WHERE id = 1;

A mensagem: NOT NULL constraint failed: clientes.nome, ou seja, "a restrição NOT NULL falhou: clientes.nome". O SQLite se recusou a deixar a coluna nome em branco. (O UPDATE, que muda dados, tem aula própria: UPDATE. No editor ele não estraga nada: cada Rodar começa com o banco limpo.)

Como consertar: uma coluna NOT NULL sempre precisa de um valor de verdade.

Nos outros bancos
  • A regra do = NULL é a mesma no MySQL, no PostgreSQL e no SQL Server: 7 = NULL dá NULL, e a forma certa é IS NULL. No SQL Server existe uma opção antiga, SET ANSI_NULLS OFF, que fazia = NULL "funcionar"; a documentação da Microsoft diz que ela está obsoleta e que, desde o SQL Server 2017, ANSI_NULLS fica sempre ligado. Não conte com ela.
  • A posição do NULL no ORDER BY muda. No MySQL, como no SQLite, os NULL vêm primeiro na ordem crescente. No PostgreSQL é o contrário: por padrão, os NULL ficam no fim da ordem crescente e no começo da decrescente; ele também aceita NULLS FIRST e NULLS LAST. Se a posição importa, escreva NULLS FIRST/NULLS LAST no SQLite e no PostgreSQL, em vez de depender do padrão.
  • Igualdade que aceita NULL. Para comparar dois valores tratando NULL como igual a NULL, o PostgreSQL usa IS NOT DISTINCT FROM (do SQL padrão) e o MySQL tem o operador <=>. Isso fica para a próxima aula.

Referência rápida

ExpressãoResultadoPor quê
NULL = NULLNULLDois desconhecidos podem ou não ser iguais
x = NULL, x <> NULL, x > NULLNULLComparar com desconhecido dá desconhecido
NULL AND 00Um lado falso já basta
NULL AND 1NULLDepende do desconhecido
NULL OR 11Um lado verdadeiro já basta
NULL OR 0NULLDepende do desconhecido
NOT NULLNULLO contrário de "não sei" é "não sei"
10 + NULL, 'a' || NULLNULLConta com desconhecido
typeof(NULL)nullTipo próprio; '' e 'NULL' são text
WHERE condiçãoSó passa o verdadeiroFalso e NULL ficam de fora
ORDER BY colunaNULL primeiro (no SQLite)Use NULLS LAST para mudar
.nullvalue TEXTOMostra o NULL no terminalComando do programa sqlite3, não SQL

Exercícios

1. O cliente 7 tem email NULL. O que isso quer dizer?

2. Quantas linhas SELECT nome FROM clientes WHERE email = NULL; devolve, sabendo que 3 clientes não têm email?

3. Verdadeiro, falso ou desconhecido?

Escreva o resultado que o SQLite mostra (1, 0 ou NULL):

NULL OR 1 →
NULL AND 0 →
NULL = NULL →

4. Quanto dá SELECT 5 * NULL;?

5. A Aurora tem 6 fornecedores, e 2 têm estado NULL. WHERE estado = 'PI' traz 2. Quantos traz WHERE estado <> 'PI'?

Missão final: os fornecedores de fora do Piauí

Missão: a Ana quer todos os fornecedores que não ficam no Piauí, inclusive os estrangeiros. A consulta abaixo só traz 2, porque os estrangeiros têm estado NULL. Faça ela trazer os 4. Dica: os estrangeiros podem ser achados por outra coluna que não tem NULL, a pais, ou pelo IS NULL que você viu de relance nesta aula.

SELECT nome, estado, pais
FROM fornecedores
WHERE estado <> 'PI';
SELECT nome, estado, pais
FROM fornecedores
WHERE estado <> 'PI' OR pais <> 'Brasil';

As duas soluções funcionam: WHERE estado <> 'PI' OR pais <> 'Brasil' e WHERE estado <> 'PI' OR estado IS NULL. Na primeira, para a Lusitana, fica "não sei OR verdadeiro", que é verdadeiro.


Resumo

  • NULL é a falta de valor: desconhecido, ainda não aconteceu ou não se aplica. Não é 0, nem '', nem 'NULL'.
  • Comparar qualquer coisa com NULL (até NULL = NULL) dá NULL, o "não sei". Por isso WHERE x = NULL e WHERE x <> NULL devolvem zero linhas, sem erro.
  • O SQL usa três valores: verdadeiro, falso e desconhecido. NULL AND 0 = 0, NULL OR 1 = 1; o resto com NULL dá NULL.
  • O WHERE só deixa passar o verdadeiro. Linhas com NULL somem tanto do "sim" quanto do "não": o total pode não fechar.
  • Contas e textos com NULL viram NULL. No ORDER BY do SQLite, o NULL vem primeiro; no DISTINCT, os NULL viram um grupo só.
  • No terminal, o NULL aparece em branco; .nullvalue NULL mostra. Para procurar, use IS NULL: é a próxima aula.