Informática

NULL no SQL e a lógica de três valores: pegadinhas resolvidas

NULL não é zero, não é texto vazio e não é “falso”: significa valor ausente ou desconhecido. Essa definição simples gera uma lógica própria, com três resultados possíveis (verdadeiro, falso e desconhecido), e é a fonte de muitas pegadinhas de prova. Todos os resultados abaixo foram obtidos executando as consultas em um banco de teste, com dados fictícios.

Os dados

Duas tabelas pequenas. Em servidor, as colunas horas_extras e unidade_id aceitam NULL.

id nome unidade_id horas_extras
1 Ana Lima 1 10
2 Bruno Souza 1 4
3 Carla Dias 2 NULL
4 Diego Alves 2 8
5 Elisa Rocha 3 0
6 Fabio Nunes NULL 6
7 Gabi Matos 2 NULL

Em unidade: 1 Protocolo, 2 Compras, 3 Arquivo, 4 Ouvidoria.

Comparar com NULL dá “desconhecido”

Qualquer comparação com NULL, inclusive NULL = NULL, resulta em desconhecido. O WHERE só mantém linhas em que a condição é verdadeira; desconhecido é descartado, como o falso.

SELECT nome FROM servidor WHERE horas_extras = NULL;

Resultado: nenhuma linha. O teste correto é IS NULL:

SELECT nome FROM servidor WHERE horas_extras IS NULL;

Resultado: Carla Dias e Gabi Matos. O inverso é IS NOT NULL. Escrever <> NULL falha pelo mesmo motivo de = NULL.

A lógica de três valores

A B A AND B A OR B
verdadeiro desconhecido desconhecido verdadeiro
falso desconhecido falso desconhecido
desconhecido desconhecido desconhecido desconhecido

E NOT desconhecido continua desconhecido. Regra prática: OR com algo verdadeiro basta para ser verdadeiro; AND com algo falso basta para ser falso; fora disso, o desconhecido contamina o resultado.

A pegadinha do “diferente de”

SELECT nome FROM servidor WHERE horas_extras <> 0;

Devolve Ana, Bruno, Diego e Fabio: quatro linhas. Carla e Gabi não aparecem, embora “não tenham zero hora extra”, porque NULL <> 0 é desconhecido. Elisa fica fora por ter exatamente zero. Para incluir os ausentes:

SELECT nome FROM servidor WHERE horas_extras <> 0 OR horas_extras IS NULL;

Agora saem seis linhas: todos menos Elisa.

Agregações e NULL

As funções de agregação ignoram NULL, com a exceção de COUNT(*).

Expressão Resultado Motivo
COUNT(*) 7 conta linhas
COUNT(horas_extras) 5 só não nulos
SUM(horas_extras) 28 10+4+8+0+6
AVG(horas_extras) 5,6 28 dividido por 5
AVG(COALESCE(horas_extras, 0)) 4,0 28 dividido por 7

COALESCE(a, b, ...) devolve o primeiro argumento não nulo. É a ferramenta para substituir ausência por um valor padrão. Se todos os valores de uma coluna forem NULL, SUM e AVG devolvem NULL, não zero.

Operações aritméticas com NULL também resultam em NULL: horas_extras + 1 para Carla dá NULL, não 1.

O caso do NOT IN

Esta é a pegadinha mais valiosa. Queremos os servidores que não estão na unidade Compras (id 2).

SELECT nome FROM servidor
WHERE unidade_id NOT IN (SELECT id FROM unidade WHERE nome = 'Compras');

Resultado: Ana, Bruno e Elisa. Fabio, que não tem unidade, não aparece: a comparação NULL NOT IN (2) é desconhecida. Isso pode ser exatamente o que se quer, ou não.

Agora o pior cenário, quando a própria lista contém NULL:

SELECT nome FROM servidor WHERE unidade_id NOT IN (1, NULL);

Resultado: nenhuma linha, para qualquer servidor. Pois x NOT IN (1, NULL) equivale a x <> 1 AND x <> NULL; o segundo termo é sempre desconhecido, então a conjunção nunca é verdadeira. Com subconsultas, basta uma linha NULL no retorno para a consulta inteira esvaziar. A alternativa segura é NOT EXISTS:

SELECT nome FROM servidor
WHERE NOT EXISTS (SELECT 1 FROM unidade u
                  WHERE u.id = servidor.unidade_id AND u.nome = 'Compras');

Resultado: Ana, Bruno, Elisa e Fabio. Aqui Fabio entra, pois não existe unidade Compras para ele. Duas consultas “equivalentes” devolveram resultados diferentes; saber por quê é o que a banca avalia.

Restrições e NULL

  • PRIMARY KEY não admite NULL.
  • NOT NULL proíbe a ausência: no teste, inserir NULL em uma coluna NOT NULL gerou erro de restrição.
  • UNIQUE aceita NULL em muitos sistemas, e o comportamento com vários NULL varia; confira o sistema citado.
  • Chave estrangeira com NULL significa “sem relacionamento”, como no caso de Fabio.

Passo a passo para questões com NULL

  1. Marque na tabela quais células são NULL.
  2. Para cada linha, avalie a condição como verdadeiro, falso ou desconhecido.
  3. Mantenha somente as verdadeiras.
  4. Em agregações, exclua os NULL do cálculo, exceto em COUNT(*).
  5. Desconfie de NOT IN, <> e = com colunas que aceitam NULL.

Erros comuns

  • Escrever = NULL ou <> NULL.
  • Achar que COUNT(coluna) conta nulos.
  • Confundir NULL com zero ou com string vazia.
  • Usar NOT IN com subconsulta que pode devolver NULL.
  • Supor que AVG divide pelo total de linhas.

Fontes e atualização

Não há norma oficial brasileira sobre a linguagem SQL. O conteúdo segue o padrão da linguagem e a prática dos sistemas gerenciadores; a lógica de três valores faz parte desse padrão, e os resultados foram conferidos por execução. Alguns detalhes (ordenação de NULL, UNIQUE com NULL) variam por sistema: confira o edital.

Próximos passos

Leia também

Para continuar no site

Viu algo errado, desatualizado ou confuso? Relatar erro nesta página