Valores SQL NULL explicados: IS NULL, COALESCE, NULLIF e as armadilhas a serem evitadas

  1. Início
  2. Blog
  3. Bancos de dados e SQL

Bancos de dados e SQL

Valores SQL NULL explicados: IS NULL, COALESCE, NULLIF e as armadilhas a serem evitadas

NULL causa alguns dos bugs mais silenciosos do SQL, com consultas que são executadas sem erros, mas perdem linhas ou distorcem as médias. Aprenda como o NULL realmente se comporta, com exemplos testados, e como lidar com isso com segurança.

9 min de leitura
Valores SQL NULL explicados: IS NULL, COALESCE, NULLIF e as armadilhas a serem evitadas

Principais pontos

  • NULL significa um valor ausente ou desconhecido. Não é zero e não é uma string vazia.
  • Teste com IS NULL, porque = NULL nunca corresponde a nada.
  • A maioria dos cálculos com NULL fornece NULL e WHERE mantém apenas linhas que são definitivamente verdadeiras.
  • Os agregados ignoram NULLs, o que pode alterar silenciosamente uma média.

Uma consulta é executada sem erros e retorna um número aparentemente sensato, mas faltam linhas e a média está errada. Valores SQL NULL são muitas vezes a causa. NULL não se comporta como nenhum valor normal e isso surpreende tanto iniciantes quanto desenvolvedores experientes.

Este guia mostra exatamente como o NULL se comporta. Executamos todas as consultas no SQLite 3.50 e os resultados mostrados vêm dessa execução. A maior parte desse comportamento é SQL padrão e observamos onde os bancos de dados diferem, como a ordem de classificação NULL e o tratamento de strings vazias pelo Oracle.

O que é NULO?

NULL é um marcador que significa que um valor está faltando ou é desconhecido. Não é um valor no sentido usual, então são coisas diferentes:

Valor Significado Exemplo para uma coluna de telefone
NULO Desconhecido ou não fornecido Não sabemos o número
'' Um valor de texto vazio e conhecido Enviado em branco
0 O número zero Não é relevante para o texto, mas é real para valores

A diferença é importante especialmente para os valores. Um bônus de 0 significa que a pessoa não recebeu nada. Um bônus NULL significa que ninguém sabe ainda.

A tabela de amostra

CREATE TABLE employees (
  id INT, name TEXT, phone TEXT, bonus INT, manager_id INT
);

INSERT INTO employees VALUES
 (1,'Meera','555-0101',500,NULL),
 (2,'Arjun',NULL,300,1),
 (3,'Sara','',NULL,1),
 (4,'Ravi',NULL,NULL,2);

Observe que Sara possui uma string vazia para o telefone, enquanto Arjun e Ravi possuem NULL. Os dois são tratados de forma muito diferente.

Testando para NULL

Aqui está o erro que quase todo mundo comete no início:

SELECT name FROM employees WHERE phone = NULL;
-- (no rows)

SELECT name FROM employees WHERE phone IS NULL;
-- Arjun
-- Ravi

SELECT name FROM employees WHERE phone IS NOT NULL;
-- Meera
-- Sara

A primeira consulta é SQL válida e não apresenta erros. Simplesmente não retorna nada, porque comparar qualquer coisa com NULL nunca é verdade. Sara aparece em IS NOT NULL, pois uma string vazia é um valor real. No Oracle, porém, uma string vazia é tratada como NULL, o que é uma exceção notável.

Lógica de três valores

Na maioria das linguagens de programação, uma condição é verdadeira ou falsa. SQL adiciona um terceiro resultado: desconhecido. Se você não conhece um valor, não pode dizer se ele é igual a 5. E dois valores desconhecidos não são iguais, e é por isso que NULL = NULL não é verdadeiro. Em nosso teste, todos retornaram NULL:

SELECT NULL = NULL, NULL <> 1, 1 + NULL, 'a' || NULL;

-- NULL | NULL | NULL | NULL

A combinação de condições segue regras cuidadosas. Aqui estão os resultados da nossa execução, onde 1 é verdadeiro e 0 é falso:

Expressão Resultado Por que
VERDADEIRO E NULO NULO Depende da parte desconhecida
FALSO E NULO Falso Falso seja qual for o desconhecido
VERDADEIRO OU NULO Verdadeiro Verdadeiro seja qual for o desconhecido
FALSO OU NULO NULO Depende da parte desconhecida
NÃO NULO NULO O oposto de desconhecido é desconhecido

Linhas que desaparecem de WHERE

WHERE mantém uma linha somente se sua condição for verdadeira. As linhas onde o resultado é desconhecido são eliminadas, juntamente com aquelas que são falsas. Isso leva a resultados surpreendentes:

SELECT name FROM employees WHERE phone <> '555-0101';

-- Sara

Você pode esperar que Arjun e Ravi apareçam, já que o telefone deles certamente não é esse número. Mas o telefone deles é desconhecido, então o resultado é desconhecido e eles desaparecem. Para incluí-los, diga explicitamente: WHERE phone <> '555-0101' OR phone IS NULL. A negação também não ajuda:

SELECT name FROM employees WHERE NOT (bonus > 400);

-- Arjun

Sara e Ravi não têm bônus, então não aparecem nem em bonus > 400 nem no oposto. Isto é algo importante a lembrar: uma condição e sua negação nem sempre cobrem todas as linhas.

COALESCE: fornece um substituto

COALESCE retorna o primeiro valor não NULL em sua lista e funciona em todos os principais bancos de dados:

SELECT COALESCE(NULL, NULL, 'third', 'fourth');
-- third

SELECT name, COALESCE(phone, 'no phone') FROM employees;
-- Meera | 555-0101
-- Arjun | no phone
-- Sara  |
-- Ravi  | no phone

Sara ainda aparece em branco porque uma string vazia não é NULL. Existem funções semelhantes, como IFNULL no MySQL e SQLite, ISNULL no SQL Server e NVL no Oracle. COALESCE é a escolha portátil. Nosso ponto anterior sobre cálculos também se aplica aqui. bonus + 100 dá NULL para qualquer pessoa sem bônus, então escreva COALESCE(bonus, 0) + 100 se tratar um bônus faltante como zero for correto para o seu negócio.

NULLIF: transforma um valor em NULL

NULLIF(a, b) retorna NULL se os dois valores forem iguais e, caso contrário, retorna a. Dois usos são especialmente úteis. Ele pode limpar valores de espaço reservado:

SELECT name, NULLIF(phone, '') FROM employees WHERE id = 3;
-- Sara | NULL

SELECT name FROM employees
WHERE COALESCE(NULLIF(phone, ''), '') = '';
-- Arjun
-- Sara
-- Ravi

Essa segunda consulta é uma maneira prática de encontrar valores “ausentes ou em branco”. Também pode proteger contra a divisão por zero, o que gera um erro em muitos bancos de dados:

SELECT total / NULLIF(quantity, 0) FROM sales;

Quando quantity é 0, isso fornece NULL em vez de falhar. Em nosso teste, SELECT 100 / NULLIF(0, 0) retornou NULL.

Agregados ignoram NULL

É aqui que NULL causa mais danos aos relatórios:

SELECT COUNT(*), COUNT(bonus), SUM(bonus), AVG(bonus),
       AVG(COALESCE(bonus, 0))
FROM employees;

-- 4 | 2 | 800 | 400.0 | 200.0
Expressão Resultado O que isso significa
COUNT(*) 4 Todas as linhas
COUNT(bonus) 2 Somente linhas com bônus
SUM(bonus) 800 NULLs são ignorados
AVG(bonus) 400 800 dividido por 2, não por 4
AVG(COALESCE(bônus, 0)) 200 800 dividido por 4

Então, qual é o bônus médio, 400 ou 200? Depende do que NULL significa nos seus dados. Se NULL significa “nenhum bônus foi pago”, então 200 está certo. Se significar “ainda não decidido”, então 400 pode estar certo. O banco de dados não pode tomar essa decisão por você, então a pergunta deve ir para alguém que conheça o negócio.

Uma armadilha relacionada: SUM sem valores é NULL em vez de 0. Quando somamos apenas as linhas sem bônus, obtemos NULL, enquanto COUNT retornou 0. O código do aplicativo que espera um número pode falhar nisso, então envolva-o: COALESCE(SUM(bonus), 0).

Dica: quando o total do relatório parecer errado, compare COUNT(*) com COUNT(column). Qualquer lacuna entre eles informa imediatamente quantos NULLs aquela coluna possui.

GROUP BY, classificação e DISTINCT

Embora NULLs “não sejam iguais” nas comparações, essas operações os tratam como um grupo:

SELECT bonus, COUNT(*) FROM employees GROUP BY bonus ORDER BY bonus;
-- NULL | 2
--  300 | 1
--  500 | 1

SELECT DISTINCT bonus FROM employees;
-- 500, 300, NULL

Consulte SQL GROUP BY e HAVING para obter mais informações sobre agrupamento. A ordem de classificação é onde os bancos de dados realmente diferem. SQLite e MySQL tratam NULL como o menor valor, enquanto PostgreSQL e Oracle o tratam como o maior. Então o mesmo ORDER BY bonus DESC pode colocar NULLs por último em um e primeiro em outro. PostgreSQL, Oracle e SQLite moderno permitem afirmar isso diretamente, usando NULLS FIRST ou NULLS LAST.

Junta-se

Uma condição de junção usando = nunca corresponde a NULL, então linhas com uma chave NULL são eliminadas de uma junção interna:

SELECT e.name FROM employees e
JOIN employees m ON m.id = e.manager_id;
-- Arjun, Sara, Ravi    (Meera is gone)

SELECT e.name, m.name FROM employees e
LEFT JOIN employees m ON m.id = e.manager_id;
-- Meera | NULL
-- Arjun | Meera
-- Sara  | Meera
-- Ravi  | Arjun

Meera não tem gerente, portanto, uma junção interna elimina silenciosamente essa linha. Um LEFT JOIN o mantém e também cria seus próprios NULLs para o lado ausente. Leia mais em Explicação sobre junções SQL.

A armadilha NÃO ESTÁ

Um único NULL em uma lista NOT IN elimina todos os resultados:

SELECT name FROM employees WHERE manager_id NOT IN (1);
-- Ravi

SELECT name FROM employees WHERE manager_id NOT IN (1, NULL);
-- (no rows)

A segunda forma significa manager_id <> 1 AND manager_id <> NULL, e a última parte nunca pode ser verdadeira. Isto é particularmente perigoso com subconsultas, onde um NULL pode chegar despercebido. Use NOT EXISTS, conforme explicado em nosso tutorial de subconsultas SQL. Meera também está faltando no primeiro resultado, já que manager_id dessa linha é NULL.

Projetando com NULL

  • Use NOT NULL por padrão. Permita NULL somente quando um valor realmente estiver faltando.
  • Adicione padrões razoáveis. Por exemplo, quantity INT NOT NULL DEFAULT 0.
  • Não use valores mágicos. Uma data de 1900-01-01 ou uma idade de -1 substituindo “desconhecido” corromperá seus cálculos.
  • Conheça o comportamento UNIQUE. A maioria dos bancos de dados permite vários NULLs em uma coluna UNIQUE, e nosso teste inseriu dois sem erro. O SQL Server é uma exceção, pois normalmente permite.
  • Lembre-se de que uma chave primária não pode ser NULA. Consulte chave primária versus chave estrangeira.
  • Teste com NULLs. Dados de teste sem NULLs ocultam esses bugs. Inclua-os propositalmente, como faria com outros casos extremos.

Considerações finais

Trate NULL como “desconhecido” e a maior parte de seu comportamento começa a fazer sentido: desconhecido mais um é desconhecido e desconhecido é igual a desconhecido não é conhecido como verdadeiro. Audite um de seus próprios relatórios esta semana. Verifique as colunas anuláveis ​​usando COUNT(*) em relação a COUNT(column), procure qualquer NOT IN e decida o que NULL deve significar em cada média.

Perguntas frequentes

O que é NULO em SQL?

NULL é um marcador para um valor ausente ou desconhecido. É diferente de zero e de uma string vazia e precisa de tratamento especial nas comparações.

Por que =NULL não funciona?

Comparar qualquer coisa com NULL resulta em desconhecido em vez de verdadeiro, então WHERE descarta a linha. Use IS NULL ou IS NOT NULL para testar.

Qual é a diferença entre COALESCE e ISNULL?

COALESCE é SQL padrão e aceita muitos argumentos. ISNULL é específico do SQL Server e leva dois. Para código portátil, prefira COALESCE.

COUNT inclui valores NULL?

COUNT(*) conta todas as linhas, incluindo aquelas com NULLs. COUNT(coluna) conta apenas as linhas onde essa coluna não é NULL, o que pode fornecer um número menor.

NULL é o mesmo que uma string vazia?

Não, na maioria dos bancos de dados. Uma string vazia é um valor conhecido sem caracteres e NULL significa desconhecido. Oracle é uma exceção notável, pois trata strings vazias como NULL.

Continue aprendendo

Trabalhe com Stack Quora

Precisa de ajuda com testes, WordPress ou SEO?

Ajudamos as equipes a fornecer software melhor e a expandir seus sites. Conte-nos no que você está trabalhando e sugeriremos um próximo passo claro.

Continue lendo

Mais guias sobre testes, IA e desenvolvimento moderno

Gostou deste artigo? Escolha um tópico e vá direto para nossos tutoriais mais recentes.

Inteligência artificial

Explicação das alucinações de IA: por que os modelos de linguagem inventam as coisas e como reduzi-las

Explicação das alucinações de IA: o que são, por que os modelos de linguagem as produzem, tipos comuns, como reduzi-las com aterramento e instruções…

Leia o artigo →
DevOps

Variáveis de ambiente explicadas: arquivos .env, segredos e configuração bem feitos

Variáveis de ambiente explicadas com exemplos de Python que executamos: leitura e configuração, por que cada valor é uma string, arquivos .env, hera…

Leia o artigo →
Desenvolvimento de software

Explicação da limitação de taxa de API: algoritmos, cabeçalhos e tratamento de erros 429

Limitação de taxa de API explicada com uma simulação que executamos: token bucket, janela fixa, janela deslizante, 429 respostas, cabeçalhos de limi…

Leia o artigo →
Automação de testes

Zombando em Python: unittest.mock, patch e os erros que fazem os testes mentirem

Zombaria em Python com unittest.mock, testado: Mock e return_value, side_effect, patch onde um nome é usado, especificação e autospec, zombaria de d…

Leia o artigo →
Teste de software

Cobertura de código explicada: cobertura de linha versus filial e o que 100% realmente significa

Cobertura de código explicada com uma execução cobertura.py real: cobertura de linha, ramal e condição, leitura de um relatório, por que 100% de cob…

Leia o artigo →
Bancos de dados e SQL

DELETE vs TRUNCATE vs DROP em SQL: diferenças, reversão e quando usar cada um

DELETE vs TRUNCATE vs DROP explicado com SQL testado: o que cada um remove, rollback, aciona, redefinição de identidade, velocidade e como PostgreSQ…

Leia o artigo →
Bancos de dados e SQL

Exibições SQL explicadas: crie, use e evite as armadilhas, com exemplos

Visualizações SQL explicadas com consultas que executamos: criação de uma visualização, resultados ao vivo, ocultação de colunas, desempenho, visual…

Leia o artigo →
Desenvolvimento de software

Interface TypeScript vs tipo: diferenças reais, testadas com o compilador

Interface TypeScript versus tipo, verificada com o compilador real: o que ambos podem fazer, o que apenas um pode fazer, mesclagem de declarações, e…

Leia o artigo →
Desenvolvimento de software

Python *args e **kwargs explicados: funções flexíveis com exemplos claros

Python *args e **kwargs explicados com o código que executamos: empacotamento e descompactação, ordem dos parâmetros, argumentos somente de palavras…

Leia o artigo →
Desenvolvimento de software

Funções Python Lambda: sintaxe, usos reais e quando não usá-los

Funções lambda do Python explicadas com o código que executamos: sintaxe, classificação com chave, mapa e filtro, fechamentos, armadilha de ligação …

Leia o artigo →
Inteligência artificial

O que são agentes de IA? Como eles funcionam, com um loop de agente simples que você pode executar

O que são agentes de IA? Um guia simples para o loop do agente, ferramentas, memória e proteções, com um pequeno loop Python que executamos, riscos …

Leia o artigo →
DevOps

Monitoramento versus observabilidade: a verdadeira diferença, com logs, métricas e rastreamentos

Explicação do monitoramento versus observabilidade: falhas conhecidas e desconhecidas, logs, métricas e rastreamentos, um passo a passo do incidente…

Leia o artigo →
DevOps

Docker Volumes vs Bind Mounts: persista os dados do contêiner da maneira certa

Volumes Docker versus montagens de ligação explicadas: por que os dados do contêiner desaparecem, volumes nomeados, montagens de ligação, tmpfs, exe…

Leia o artigo →
Automação de testes

TDD vs BDD: principais diferenças, um recurso criado de ambas as maneiras e quando usar cada um

TDD vs BDD explicado com um recurso de desconto construído em ambos os sentidos: refatoração vermelho-verde com o código que executamos, cenários da…

Leia o artigo →
Teste de software

Teste de aceitação do usuário (UAT): processo, lista de verificação e exemplos reais

Explicação do teste de aceitação do usuário: quem o executa, como ele difere do controle de qualidade, um processo de sete etapas, um modelo de caso…

Leia o artigo →
Bancos de dados e SQL

Valores SQL NULL explicados: IS NULL, COALESCE, NULLIF e as armadilhas a serem evitadas

Valores SQL NULL explicados com consultas que executamos: lógica de três valores, IS NULL, COALESCE, NULLIF, como agregações, junções e classificaçã…

Leia o artigo →
Bancos de dados e SQL

Instrução SQL CASE WHEN: sintaxe, exemplos reais e erros comuns

SQL CASE WHEN explicado com consultas que executamos: formulários simples e pesquisados, ordem de condição, pivôs com SUM, truques COUNT, classifica…

Leia o artigo →
Desenvolvimento de software

O que é JWT? JSON Web Tokens explicados com um exemplo prático

O que é JWT? JSON Web Tokens explicados: as três partes, um token construído e adulterado no código que executamos, JWT vs sessões, armazenamento, t…

Leia o artigo →
Desenvolvimento de software

Loop de eventos JavaScript explicado: pilha de chamadas, microtarefas e temporizadores com exemplos

O loop de eventos JavaScript explicado com o código que executamos: pilha de chamadas, filas de tarefas e microtarefas, por que setTimeout 0 não é i…

Leia o artigo →
Desenvolvimento de software

Geradores Python e rendimento explicado: economize memória com exemplos reais

Geradores Python e rendimento explicados com o código que executamos: como eles pausam e reiniciam, medem economia de memória, pipelines, sequências…

Leia o artigo →
Inteligência artificial

O que são incorporações? Similaridade de vetores e cossenos explicada de forma simples

O que são incorporações? Um guia em linguagem simples para vetores, similaridade de cossenos e pesquisa semântica, com um pequeno exemplo que execut…

Leia o artigo →
DevOps

Implantação azul-verde vs canário: diferenças, compensações e como escolher

Explicação da implantação azul-verde versus canário: como cada um funciona, custo, risco e reversão, agrupamento estável de usuários que testamos, m…

Leia o artigo →
Automação de testes

Testes instáveis: o que os causa e como corrigi-los para sempre

Testes instáveis explicados com demonstrações que executamos: as principais causas, como confirmar e diagnosticar uma, soluções adequadas para tempo…

Leia o artigo →
Teste de software

Teste de carga versus teste de estresse: diferenças, métricas e exemplos k6

Teste de carga versus teste de estresse explicado: o que cada um prova, testes de pico e absorção, as métricas que importam, por que as médias engan…

Leia o artigo →
Teste de software

Caso de teste versus cenário de teste: principais diferenças, exemplos e quando usar cada um

Caso de teste vs cenário de teste explicado: definições claras, uma tabela lado a lado, um recurso de redefinição de senha retirado de cenários para…

Leia o artigo →
Bancos de dados e SQL

Otimização de consultas SQL: leia planos de execução e corrija consultas lentas, com intervalos

Otimização de consulta SQL testada em um milhão de linhas: leia planos de execução, adicione os índices corretos, corrija filtros não sargáveis, use…

Leia o artigo →
Bancos de dados e SQL

SQL UNION vs UNION ALL: diferenças, exemplos e desempenho testado

SQL UNION vs UNION ALL explicado com consultas que executamos: duplicatas, as regras que ambos seguem, um bug de dados real, desempenho medido, INTE…

Leia o artigo →
Desenvolvimento de software

Tutorial da API JavaScript Fetch: GET, POST, tratamento de erros e tempos limite

Um tutorial da API JavaScript Fetch testado em um servidor local: GET e POST, por que 404 não lança, um auxiliar reutilizável, strings de consulta, …

Leia o artigo →
Desenvolvimento de software

Manipulação de arquivos Python: leitura, gravação, CSV, JSON e pathlib com exemplos

Manipulação de arquivos Python explicada com código que executamos: modos abertos, com, leitura de arquivos grandes, CSV, JSON, pathlib, arquivos bi…

Leia o artigo →
Desenvolvimento de software

Classes e objetos Python: tutorial OOP com exemplos reais

Classes e objetos Python explicados com código que executamos: __init__, métodos, atributos de classe vs instância, herança, propriedades, métodos d…

Leia o artigo →
Inteligência artificial

O que é um modelo de linguagem grande? Como funcionam os LLMs, explicado sem exageros

O que é um modelo de linguagem grande? LLMs explicados em linguagem simples: tokens, incorporações, atenção, treinamento, temperatura e janelas de c…

Leia o artigo →
DevOps

Comandos Linux para iniciantes: o guia essencial do terminal com exemplos

Comandos Linux para iniciantes, agrupados por tarefa: navegação, arquivos, visualização de logs, grep, pipes, permissões, processos e arquivos, com …

Leia o artigo →
Automação de testes

Selenium vs Playwright: principais diferenças, código comparado e qual escolher

Selenium vs Playwright comparado: arquitetura, espera, suporte a navegador e linguagem, depuração, o mesmo teste em ambas as ferramentas, conselhos …

Leia o artigo →
Teste de software

Particionamento de equivalência: técnica de design de teste explicada com exemplos resolvidos

Explicação do particionamento de equivalência: como encontrar partições válidas e inválidas, exemplos resolvidos para idades, senhas e cupons, teste…

Leia o artigo →
Teste de software

Gravidade vs Prioridade em Testes de Software: Diferenças, Matriz e Exemplos Reais

Explicação da gravidade versus prioridade em testes de software: definições claras, uma matriz de quatro vias com exemplos, escalas de nível, quem d…

Leia o artigo →
Bancos de dados e SQL

Tutorial de subconsultas SQL: tipos, subconsultas correlacionadas e EXISTS com exemplos

Um tutorial de subconsultas SQL com consultas que executamos: subconsultas escalares, IN, FROM e SELECT, subconsultas correlacionadas, EXISTS, a arm…

Leia o artigo →
Bancos de dados e SQL

Transações SQL e ACID explicados: COMMIT, ROLLBACK e níveis de isolamento

Transações SQL e ACID explicadas com uma transferência bancária que executamos: COMMIT, ROLLBACK, savepoints, locks, níveis de isolamento, leituras …

Leia o artigo →
Desenvolvimento de software

Git merge vs rebase: diferenças, exemplos e quando usar cada um

Git merge vs rebase explicado com saída real do log, uma tabela comparativa, a regra de ouro do rebase e um fluxo de trabalho seguro para equipes.

Leia o artigo →
Desenvolvimento de software

List comprehension em Python: sintaxe, exemplos e quando evitar

List comprehension em Python explicada: sintaxe, filtros, if-else, laços aninhados, tempos medidos e quando um laço for comum é a melhor escolha.

Leia o artigo →
Bancos de dados e SQL

SQL JOIN explicado com exemplos (Inner, Left, Right, Full)

Entenda os joins SQL passo a passo com tabelas e consultas de exemplo: INNER, LEFT, RIGHT, FULL, CROSS e SELF, além de erros comuns e dicas de desem…

Leia o artigo →