Sabemos que Edgar Codd propôs dois modelos de distinção para um valor nulo (missing value):

  • Nulo mas aplicável (missing but applicable; A- Values Marker)
  • Nulo porém inaplicável (missing but inapplicable; I- Values Marker)

Para facilitar o exemplo, imagine o seguinte cenário com uma tabela que contém três colunas:

Nome, nome do meio e sobrenome – sabendo que as colunas nome e sobrenome são not nulls.

Como a coluna nome do meio é opcional de cada “cliente” e pode receber nulo, teríamos a aplicação de dois cenários aqui:

  • A-Values Marker – quando um cliente tem nome do meio mas não explicita ou, opta por não utilizar
  • I-Values Marker – quando não há de fato nome do meio para um determinado cliente

Como os arquitetos da linguagem SQL não queriam especificar um token para cada tipo de valor, declararam o null como único para ambos os casos. O que se mostrou um ‘erro’ quando surgiram as funções de cube e rollup.

Então, assumam como uma boa prática utilizar not null em todas as colunas que são explicitamente proibidas de ter valor null, como exemplo: RG, Nome, Sobrenome, CPF etc.

Revisão a comparação

Comparações com where, on e having devem considerar nulls em seus resultados por ser sempre uma possível saída na query em sua grande maioria.

Veja este exemplo sobre a consideração dos nulos em seus resultados.

Adicionando o devido tratamento para possível null na query.

O que eu quis mostrar nesta query foi a inconsistência do resultado quando uma coluna permite valores nulos em seus registros.

Quando temos este tipo de situação em uma tabela, temos de pensar na possibilidade de ali ter nulls em suas linhas e caso tenha, adicionar o tratamento adequado para que o resultado seja condizente.

Se executarem a primeira query, verão que quando ela exclui os valores desconhecidos devido a forma como o SQL Server lida com a avaliação do resultado: ‘True or False’.

Comparando com variáveis, parâmetros e colunas

SQL não lida de uma forma diferente quando compara null com variáveis ou parâmetros o tratamento dado para ambos é o mesmo e simples. Veja:

A solução para o problema acima seria utilizar isnull junto com o where, o que causaria uma certa queda no desempenho do index desta busca.

Aqui nesta query estamos atribuindo a coluna shippeddate e seus valores nulos a data máxima permitida e o mesmo para a variável @DTE. Com isso, podemos comparar as duas na cláusula where.

Lembrem-se sempre que o SQL Server não processa coluna = null.

Para solucionar de fato este problema existem duas soluções que trariam ótimos resultados, ainda que a primeira, dependendo do tipo de filtro e query, poderia se tornar extremamente confusa e a segunda, podemos utilizar a função ansi_null off, como visto no post anterior.

A função desabilita o comportamento padrão do SQL Server permitindo que ele faça comparações de true e false com nulls.

A MS não recomenda e inclusive indicou que iria retirar esse suporte a alteração de padrões de comportamento do SQL Server. Então, se for utilizar a função ansi_nulls, faça com cuidado e garanta que será habilitado ao final da query.

Revisão alguns conceitos de comparação de valores com nulos, não devemos esquecer e que inclusive, não foi dito no post anterior, como retornar nulls em consultas que envolvam joins de tabelas?

Tendo em mente e já tendo um post sobre joins aqui no blog, sabemos que quando utilizamos o inner join, todos os valores nulos são excluídos do resultado; mas e se quiséssemos incluí-los na consulta, como poderíamos contornar essa situação?

Veja no primeiro exemplo como a query foi elaborada. (no script há o bloco de comando utilizado para criar e popular a tabela do banco).

Claramente podemos ver que o resultado não foi mostrado por termos colunas que possuíam nulos em suas linhas e foram utilizadas como parâmetro de comparação.

Agora, substituindo os possíveis nulos utilizando a função isnull, temos outra perspectiva de resultado.

Existe uma outra técnica que foi descoberta e documentada por um dos maiores MVPs de SQL Server e Data Plataform da MS que se chama Paul White, na descoberta, ele se baseou na função intersect e exists para formular essa solução. Veja abaixo a query:

Como a subquery retorna apenas a interseção entre as duas queries e manda o resultado para a query externa que pede apenas valores que existam na query interna, temos esse resultado como se estivéssemos digitado where @DT = NULL; com plena execução do SQL Server.

Ao final deste post, deixarei o script dos exemplos aqui citados e com mais exemplos baseados na solução do Paul White!

CONCLUSÃO

Este foi um post continuando o assunto sobre o tratamento de nulls SQL Server e como ele opera logicamente quando recebe esse tipo de valor.

Também abordei soluções alternativas para esse tipo de problema quando temos um cenário que envolve variáveis dentro da consulta no banco.

Para o próximo irei encerrar temporariamente a série de posts sobre nulls com inconsistências em blocos de programação e com funções de agregação!

Link para o script!

Espero que tenham gostado, saúde!