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".
- O que é o
NULL: um valor desconhecido ou que não existe. - Por que
NULLnão é zero, nem texto vazio, nem a palavra'NULL'. - Onde o
NULLaparece na Loja Aurora, no editor e no terminal dosqlite3. - Por que
WHERE email = NULLdevolve zero linhas, sem dar erro. - A lógica de três valores: como
AND,OReNOTse comportam com o "não sei". - O que acontece com o
NULLnuma conta, numa ordenação e numDISTINCT.
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 papel | No banco | Quer dizer |
|---|---|---|
| Campo em branco | NULL | Não sabemos / não existe |
| "0" escrito no campo | 0 | Sabemos, 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 coluna | Quem tem NULL | Por quê |
|---|---|---|
clientes.email | Clientes 7, 15 e 23 | Não deram email |
clientes.nascimento | Clientes 9 e 21 | Data de nascimento não informada |
fornecedores.estado | Fornecedores 4 (Portugal) e 5 (Argentina) | Não existe "estado brasileiro" fora do Brasil |
pedidos.entregue_em | Pedidos 86 a 90 | Ainda não foram entregues |
funcionarios.chefe_id | Funcionária 1, a gerente | Ela 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 valorNULL.
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.
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:
NULL AND 0→0. OANDprecisa que os dois lados sejam verdadeiros. Um lado já é falso, então não importa a carta virada: o resultado é falso.NULL AND 1→ NULL. Um lado é verdadeiro; o resultado depende da carta virada. Não sei.NULL OR 1→1. OORprecisa de um lado verdadeiro. Já tem um, então é verdadeiro, seja qual for a carta.NULL OR 0→ NULL. Um lado é falso; tudo depende da carta virada. Não sei.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):
| a | b | a AND b | a OR b |
|---|---|---|---|
| V | V | V | V |
| V | F | F | V |
| V | ? | ? | V |
| F | F | F | F |
| F | ? | F | ? |
| ? | ? | ? | ? |
| a | NOT a |
|---|---|
| V | F |
| F | V |
| ? | ? |
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ê quer | Escreva | Não escreva |
|---|---|---|
| Achar quem não tem email | WHERE email IS NULL (próxima aula) | WHERE email = NULL (sempre 0 linhas) |
| Achar quem tem email | WHERE email IS NOT NULL | WHERE email <> NULL (sempre 0 linhas) |
| Dividir a tabela em "sim" e "não" sem perder ninguém | Pense no terceiro grupo: ... OR estado IS NULL | Só estado = 'PI' e estado <> 'PI' |
| Mostrar um texto no lugar do branco | IFNULL(email, 'sem email') (aula IFNULL e COALESCE) | email || '' (continua NULL) |
Ver o NULL no terminal | .nullvalue NULL | Procurar o texto 'NULL' com WHERE email = 'NULL' |
| Guardar "não tem" como informação | Decida e documente: NULL = desconhecido; 0 ou '' = sabido | Misturar 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.
= 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).
'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.
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).
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.
- A regra do
= NULLé a mesma no MySQL, no PostgreSQL e no SQL Server:7 = NULLdá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_NULLSfica sempre ligado. Não conte com ela. - A posição do NULL no
ORDER BYmuda. No MySQL, como no SQLite, osNULLvêm primeiro na ordem crescente. No PostgreSQL é o contrário: por padrão, osNULLficam no fim da ordem crescente e no começo da decrescente; ele também aceitaNULLS FIRSTeNULLS LAST. Se a posição importa, escrevaNULLS FIRST/NULLS LASTno SQLite e no PostgreSQL, em vez de depender do padrão. - Igualdade que aceita NULL. Para comparar dois valores tratando
NULLcomo igual aNULL, o PostgreSQL usaIS 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ão | Resultado | Por quê |
|---|---|---|
NULL = NULL | NULL | Dois desconhecidos podem ou não ser iguais |
x = NULL, x <> NULL, x > NULL | NULL | Comparar com desconhecido dá desconhecido |
NULL AND 0 | 0 | Um lado falso já basta |
NULL AND 1 | NULL | Depende do desconhecido |
NULL OR 1 | 1 | Um lado verdadeiro já basta |
NULL OR 0 | NULL | Depende do desconhecido |
NOT NULL | NULL | O contrário de "não sei" é "não sei" |
10 + NULL, 'a' || NULL | NULL | Conta com desconhecido |
typeof(NULL) | null | Tipo próprio; '' e 'NULL' são text |
WHERE condição | Só passa o verdadeiro | Falso e NULL ficam de fora |
ORDER BY coluna | NULL primeiro (no SQLite) | Use NULLS LAST para mudar |
.nullvalue TEXTO | Mostra o NULL no terminal | Comando 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 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 issoWHERE x = NULLeWHERE x <> NULLdevolvem zero linhas, sem erro. - O SQL usa três valores: verdadeiro, falso e desconhecido.
NULL AND 0= 0,NULL OR 1= 1; o resto comNULLdáNULL. - O
WHEREsó deixa passar o verdadeiro. Linhas comNULLsomem tanto do "sim" quanto do "não": o total pode não fechar. - Contas e textos com
NULLviramNULL. NoORDER BYdo SQLite, oNULLvem primeiro; noDISTINCT, osNULLviram um grupo só. - No terminal, o
NULLaparece em branco;.nullvalue NULLmostra. Para procurar, useIS NULL: é a próxima aula.