Valores nulos ou desconhecidos sempre foram motivo de debate na área de dados, mais precisamente em banco de dados. Os mais entusiastas advogam que esse tipo de valor deveria ser melhor trabalhado dependendo da situação que se utiliza e outros que este tipo de valor seria melhor fora da linguagem SQL.

Quando em 92 a linguagem SQL foi padronizada, decidiram deixar o NULL para registros desconhecidos. Valores desconhecidos e valores vazios são diferentes. Deste modo, quando a padronização foi de fato estabelecida e todos passaram a adotar a linguagem SQL em bancos relacionais, passamos a ter três valores lógicos: True, False and Unknown(null).

TRATANDO SOBRE NULLS

Sabendo que null é um valor desconhecido ele passa a ser ‘diferente’ entre cada linha que ele apareça. Se uma determinada tabela tem em uma um registro null, este valor é totalmente desconhecido para o banco e o sistema não consegue igualar para trazer o resultado. 

Se fôssemos comparar o null  na tabela verdade, todas as suas comparações são falsas, independente do operador lógico. Por esse motivo, quase todas as funções quando trabalham com null, acabam não retornando valor.

A query abaixo corrobora com a ideia que passamos sobre null ser um valor desconhecido. Veja que existem 27659 linhas nessa tabela que não possuem um vendedor e o SQL server não consegue fazer a contagem, retornando 0 como resultado para a coluna salespersonid.

Como dito, a maioria das funções terão algum tipo de problema quando forem trabalhar com null, mas existem duas funções que lidam e foram feitas especialmente para trabalhar com null: ISNULL e COALESCE (COALESCE é padrão ISO).

Ambas as funções substituem o null por um valor passado pelo usuário na query, veja abaixo:

Note que agora o SQL Server conseguiu realizar a contagem das vendas que possuíam null como registro na coluna de vendedor, diferente do exemplo anterior que apenas retornou zero.

Inclusive, conseguimos unir a contagem retornando o valor original da primeira query. 

Ainda tratando sobre as funções de NULL, podemos mencionar uma terceira que se chama NULLIF. Essa age de uma forma diferente no resultado, se ISNULL e COALESCE substituem o nulo por algum valor, NULLIFF faz uma comparação e ‘anula’ o resultado caso sejam iguais, veja:

Uma outra forma de comparação que pode ser uma opção ao join, subquery ou um outro recurso é utilizar para comparar se um determinado registro de uma tabela existe em outra, como eu fiz nesse exemplo abaixo: 

Nesta query utilizei o left join propositalmente, para retornar os registros que não possuíam correspondência e comparar com o NULLIF. E quando não há correspondência entre as colunas utilizadas como parâmetro na query, o valor retornado é sempre o do primeiro parâmetro.

As funções de agregação não tratam nulls em suas operações. Todos os registros que encontramos como nulo na coluna, são ignorados e a operação é realizada somente por valores válidos.

A única função de agregação que considera null em suas operações é a COUNT, desde que você não passe na função a coluna que deseja realizar a contagem, veja

Isso acontece pois na primeira query, a função conta todas as linhas criadas naquela tabela. Como ela não precisa ter conhecimento do valor registrado, apenas contar, temos o total de linhas criadas nesta tabela. 

Agora, quando especificamos uma coluna, a função precisa avaliar os registros e como null é um registro desconhecido para o banco, e não possui um valor palpável como um texto ou número, o engine ignora e conta apenas as linhas que possuem registros identificáveis. 

E para título de curiosidade, veja que mesmo utilizando um filtro de is not null com o filtro having, a query continua contando as linhas com valores nulos.

PADRÃO ANSI E AS FUNÇÕES DE NULL EM COLUNAS

O padrão ANSI, quando foi criado, estipulou algumas funções de sistema que o SQL Server adota que trata sobre o comportamento de algumas atividades executadas por query no banco de dados.

Podemos por exemplo desativar a possibilidade de aceitar nulos em colunas, como uma concatenação funciona quando um dos campos unidos é nulo e por fim, como o engine do banco deve realizar a comparação com valores nulos. 

A função SET ANSI_NULL_DFLT_ON/OFF determina se as colunas da tabela que está sendo criada ou sendo configurada com essa função padrão pode aceitar nulo como padrão ou não.

Neste primeiro exemplo fiz uma consulta na configuração do banco e vi que o padrão ansi_null_dflt esta ativo, isso quer dizer que podemos passar null no insert ou criar uma constraint de null quando não houver um valor explícito no insert, que o engine do banco irá processar e registrar. 

Como podemos notar, as duas colunas aceitaram nulls no insert e a batch de comando foi concluída com sucesso. 

Agora note o que ocorre quando mudamos a configuração do banco para ANSI_NULLS_DFLT_ON OFF. Veja na imagem o retorno do erro. 

Por ter desabilitado a função, esse tipo de insert passa a ser negado pelo engine do banco e nem com constraint podemos ter nulo nas colunas.

Perceba também que as duas tabelas foram criadas como null, ou seja, aceitariam com ou sem declaração explícita, salvo o segundo exemplo.

No começo deste post expliquei que o SQL Server quando executa uma query que iguala a null no filtro where, retorna um resultado vazio. Esse tipo de resultado ocorre porque o padrão ANSI determina que a linguagem SQL haja assim mas, isso é possível de alterar com a função: SET ANSI_NULLS.

Neste bloco de exemplo, há dois selects que foram executados juntos, exatamente iguais, sendo o segundo com o ANSI_NULLS desligado. 

Quando desativado, permitiu que o SQL Server pudesse igualar o filtro da query com null, ‘descartando’ o uso da cláusula IS NULL, que continua sendo válida também. O resultado é o mesmo. 

Por fim, a última função que é capaz de alterar o comportamento do banco de dados quanto ao processamento de nulls é a função CONCAT_NULL_YIELDS_NULL.

Normalmente, quando executamos uma concatenação entre campos onde um deles é nulo, toda a operação ‘falha’, voltando como resultado null. Modificando esse comportamento com a função, o que estamos passando para o banco é que ele ignore o null e realize concatenação. 

Note que a segunda query, já com a configuração alterada, retornou a cor e o separador utilizado, mas não retornou o tamanho.

Veja que fato interessante a respeito do padrão ANSI e NULL!!

Como vimos, para o SQL Server igualar uma determinada query com null, temos que alterar a configuração do banco utilizando ANSI_NULL, mas será que isso se aplica a toda operação? A resposta é NÃO! veja o que ocorre quando executamos um update!

Não esqueça que quando for trabalhar com null em queries ou indiretamente a sua query envolva null, lembre-se sempre que a linguagem SQL avalia três situações lógicas:

true, false e unknown. Logo, se ao executar uma consulta e quiser excluir ou incluir as linhas que possuem nulls, utilize sempre IS NULL OU IS NOT NULL no filtro where ou having. 

Fazendo isso, estamos evitando o tipo de problema abaixo: 

Este foi o primeiro da minissérie de três posts que pretende tratar sobre como gerenciar da melhor forma os valores nulos nas colunas de uma tabela.

O post trata sobre todos os conceitos iniciais além de mostrar como alterar o comportamento do SQL Server para esse tipo de valor, ainda que não seja aconselhável.

No link abaixo, deixarei o arquivo de script com alguns casos para complementar este post!!

Alguns cenários e como resolver: (SCRIPT)

Espero que gostem, saúde!