IS NULL e IS NOT NULL

1. Entendendo o valor NULL no SQL

NULL em SQL representa a ausência de valor, não um valor em si. É fundamental compreender que NULL é diferente de zero (0), string vazia ('') ou qualquer outro valor. NULL significa que o dado é desconhecido, inexistente ou ainda não foi informado.

-- NULL não é igual a zero ou string vazia
SELECT NULL = 0;      -- Resultado: NULL (desconhecido)
SELECT NULL = '';     -- Resultado: NULL (desconhecido)
SELECT NULL = NULL;   -- Resultado: NULL (desconhecido)

Por definição, NULL não é igual a nada, nem mesmo a outro NULL. Isso ocorre porque o SQL utiliza lógica trivalente (verdadeiro, falso, desconhecido). Comparações com NULL sempre resultam em "desconhecido", nunca em verdadeiro ou falso.

Essa característica exige operadores especiais para verificar a presença ou ausência de NULL: IS NULL e IS NOT NULL. Os operadores comuns como = e <> simplesmente não funcionam com NULL.

2. Operador IS NULL: encontrando valores ausentes

O operador IS NULL retorna verdadeiro quando o valor da coluna é NULL. Sua sintaxe é direta:

SELECT coluna1, coluna2
FROM tabela
WHERE coluna IS NULL;

Exemplo prático 1: Encontrar clientes que não informaram telefone

SELECT id_cliente, nome, telefone
FROM clientes
WHERE telefone IS NULL;

Exemplo prático 2: Pedidos sem data de entrega registrada

SELECT id_pedido, data_pedido, data_entrega
FROM pedidos
WHERE data_entrega IS NULL;

Cuidado importante: Colunas que permitem NULL podem conter valores ausentes em qualquer registro. Sempre verifique se a coluna foi definida com a restrição NOT NULL antes de assumir que todos os registros possuem valor.

3. Operador IS NOT NULL: filtrando dados preenchidos

O operador IS NOT NULL retorna verdadeiro quando a coluna possui um valor definido (qualquer valor que não seja NULL).

SELECT coluna1, coluna2
FROM tabela
WHERE coluna IS NOT NULL;

Exemplo prático 1: Produtos com preço definido

SELECT id_produto, nome, preco
FROM produtos
WHERE preco IS NOT NULL;

Exemplo prático 2: Funcionários com e-mail cadastrado

SELECT id_funcionario, nome, email
FROM funcionarios
WHERE email IS NOT NULL;

Uso combinado com outras condições:

SELECT nome, salario, data_admissao
FROM funcionarios
WHERE salario IS NOT NULL
  AND data_admissao >= '2023-01-01';

4. NULL em expressões e funções agregadas

NULL em operações aritméticas propaga-se: qualquer operação envolvendo NULL resulta em NULL.

SELECT 10 + NULL;   -- Resultado: NULL
SELECT NULL * 5;    -- Resultado: NULL
SELECT 'Texto' || NULL;  -- Resultado: NULL (em alguns SGBDs)

Funções agregadas e NULL:

-- Tabela exemplo: vendas
-- (100, 200, NULL, 150, NULL)

SELECT COUNT(*) FROM vendas;           -- 5 (conta todas as linhas)
SELECT COUNT(valor) FROM vendas;       -- 3 (ignora NULL)
SELECT SUM(valor) FROM vendas;         -- 450 (ignora NULL)
SELECT AVG(valor) FROM vendas;         -- 150 (soma 450 / 3 registros não nulos)

Tratando NULL com COALESCE:

SELECT COALESCE(valor, 0) + 10 AS valor_ajustado
FROM vendas;
-- Se valor for NULL, usa 0; caso contrário, usa o valor original

5. Diferença entre IS NULL e outras comparações

A principal confusão entre iniciantes é usar = NULL ou <> NULL em vez de IS NULL ou IS NOT NULL.

-- ERRADO: sempre retorna vazio (ou nenhuma linha)
SELECT * FROM clientes WHERE telefone = NULL;

-- CORRETO: retorna clientes sem telefone
SELECT * FROM clientes WHERE telefone IS NULL;

-- ERRADO: sempre retorna vazio
SELECT * FROM clientes WHERE telefone <> NULL;

-- CORRETO: retorna clientes com telefone
SELECT * FROM clientes WHERE telefone IS NOT NULL;

Comparação com string vazia e zero:

-- NULL vs string vazia
SELECT * FROM clientes WHERE nome = '';     -- Encontra string vazia, não NULL
SELECT * FROM clientes WHERE nome IS NULL;  -- Encontra NULL, não string vazia

-- NULL vs zero
SELECT * FROM produtos WHERE preco = 0;     -- Encontra preço zero, não NULL
SELECT * FROM produtos WHERE preco IS NULL; -- Encontra preço ausente, não zero

6. NULL em junções (JOINs) e subconsultas

Comportamento em JOINs:

-- INNER JOIN: linhas com NULL na chave de junção são excluídas
SELECT c.nome, p.id_pedido
FROM clientes c
INNER JOIN pedidos p ON c.id_cliente = p.id_cliente;
-- Clientes sem pedidos (id_cliente NULL em pedidos) não aparecem

-- LEFT JOIN: linhas com NULL na tabela da direita são preservadas
SELECT c.nome, p.id_pedido
FROM clientes c
LEFT JOIN pedidos p ON c.id_cliente = p.id_cliente;
-- Clientes sem pedidos aparecem com id_pedido = NULL

Armadilha do NOT IN com NULL:

-- Suponha: clientes (1, 2, 3) e pedidos (1, NULL)
-- Subconsulta retorna: (1, NULL)

-- ERRADO: NOT IN com NULL na subconsulta retorna vazio
SELECT * FROM clientes
WHERE id_cliente NOT IN (SELECT id_cliente FROM pedidos);
-- Resultado: nenhuma linha (devido ao NULL)

-- CORRETO: usar NOT EXISTS
SELECT * FROM clientes c
WHERE NOT EXISTS (
    SELECT 1 FROM pedidos p
    WHERE p.id_cliente = c.id_cliente
);

7. Funções e expressões para lidar com NULL

COALESCE: Retorna o primeiro valor não nulo da lista.

SELECT COALESCE(telefone, celular, 'Sem contato') AS contato
FROM clientes;

NULLIF: Retorna NULL se dois valores forem iguais.

SELECT NULLIF(quantidade, 0) AS quantidade_ajustada
FROM itens_venda;
-- Se quantidade for 0, retorna NULL; caso contrário, retorna o valor

Funções específicas de SGBD:

-- SQL Server: ISNULL
SELECT ISNULL(telefone, 'Não informado') FROM clientes;

-- MySQL: IFNULL
SELECT IFNULL(telefone, 'Não informado') FROM clientes;

-- PostgreSQL: COALESCE (padrão ANSI)
SELECT COALESCE(telefone, 'Não informado') FROM clientes;

8. Boas práticas e desempenho com NULL

Indexação de colunas com NULL:

-- PostgreSQL: índice parcial para filtrar NULLs
CREATE INDEX idx_clientes_telefone_notnull
ON clientes (telefone)
WHERE telefone IS NOT NULL;

-- SQL Server: índice filtrado
CREATE INDEX idx_clientes_telefone_notnull
ON clientes (telefone)
WHERE telefone IS NOT NULL;

Modelagem de dados:

  • Permitir NULL quando: o valor é opcional ou ainda não conhecido (ex: data de entrega futura)
  • Evitar NULL quando: o valor é obrigatório para a lógica de negócio (ex: CPF do cliente)
  • Valores sentinela: usar valores especiais (ex: '1900-01-01' para data desconhecida) geralmente é pior que NULL, pois pode gerar confusão em relatórios

Chaves estrangeiras e NULL:

-- Evitar NULL em chaves estrangeiras quando possível
CREATE TABLE pedidos (
    id_pedido INT PRIMARY KEY,
    id_cliente INT NOT NULL,  -- Evitar NULL aqui
    FOREIGN KEY (id_cliente) REFERENCES clientes(id_cliente)
);

NULL em chaves estrangeiras pode indicar que o relacionamento é opcional, mas compromete a integridade referencial.


Referências