MySQL Trabalhando com NULL

Há alguns dias, precisei fazer uma query para trazer alguns registros de uma determinada tabela (SGBD – MySQL), para desenvolver um relatório usando a ferramenta iReport.

A tabela possuia alguns registros com campos foreign key com valor NULL – campos não obrigatórios que faziam referencias à outras tabelas.

Seguindo a regra de negócio, seria preciso filtrar os registros, pegando alguns desses campos utilizando o BETWEEN na cláusula WHERE. Desta forma, o usuário poderia selecionar um intervalo de registros para ser exibidos no relatório.

Para exemplificar, imagine a seguinte situação:

– Temos uma tabela de grupo de produtos, chamada grupo, com um campo codigo (primary key) e outro de descricao;



– Um tabela de produtos, chamada de produto… =], com os campos: codigo (primary key), descricao e grupo (foreign key);

Obs: Não é obrigatório informar um grupo para o produto.

O relatório listaria os produtos com sua respectiva descrição de grupo. Para gerar estas informações no relatório, facilmente podemos elaborar a seguinte query, para trazer todos os produtos:

SELECT p.codigo, p.descricao, g.descricao FROM produto AS p
LEFT OUTER JOIN grupo AS g
ON p.grupo = g.codigo
WHERE p.codigo BETWEEN '' AND '9999999999999'

O resultado seria este:

A query acima funciona bem! Onde, os valores para o BETWEEN na cláusula WHERE, seriam informados pelo usuário, para gerar o relatório.
Mas e se fosse preciso também, deixar o usuário filtrar uma faixa de grupo? Facil! Só incluir um outro BETWEEN para o código do grupo.

A query ficaria da seguinte forma – com uma condição a mais na cláusula WHERE, porem, abrangente o suficiente (ou o que imaginamos ser) para trazer todos os produtos:

SELECT p.codigo, p.descricao, g.descricao FROM produto AS p
LEFT OUTER JOIN grupo AS g
ON p.grupo = g.codigo
WHERE p.codigo BETWEEN '' AND '9999999999999'
AND p.grupo BETWEEN '' AND '9999999999999'

Ao executar a query acima, teríamos o seguinte resultado:

Repare que foi exibido menos registros do que era esperado. Onde estão as linhas que não possuem grupo, ou seja, as linhas cujo o conteúdo do campo grupo é NULL, mostrado no resultado anterior? Se a query anterior trouxe todos, porque está, que também deveria trazer os mesmos registros, não os trouxe?

Respostas para todas estas perguntas:
Null não se localiza entre ” (branco) e ‘9999999999999’, como imaginávamos anteriormente.

Para solucionar este problema, utilizei a função IFNULL(expressão1, expressão2), que funciona da seguinte forma:

Se a expressão1 não for nula, então a função irá retornar o valor contido na expressão1; caso contrario, ou seja, o valor da expressão1 for nulo, a função retornará o valor contido na expressão2.

Neste caso, a query reescrita ficaria assim:

SELECT p.codigo, p.descricao, g.descricao FROM produto AS p
LEFT OUTER JOIN grupo AS g
ON p.grupo = g.codigo
WHERE p.codigo BETWEEN '' AND '9999999999999'
AND IFNULL(p.grupo, '') BETWEEN '' AND '9999999999999'

E obteríamos novamente:

Temos todos os registros novamente e não temos mais o problema no BETWEEN.

Mas se em vez de mostrar null, quiséssemos mostrar um valor padrão, como “Não classificado” , por exemplo.

Nossa query ficaria assim:

SELECT p.codigo, p.descricao, IFNULL(g.descricao,'Não classificado') AS descricao FROM produto AS p
LEFT OUTER JOIN grupo AS g
ON p.grupo = g.codigo
WHERE p.codigo BETWEEN '' AND '9999999999999'
AND IFNULL(p.grupo, '') BETWEEN '' AND '9999999999999'

Que nos retornaria:

Como eu mencionei no inicio do post, a query seria utilizada no iReport e facilmente poderia configurar a propriedade do campo para mostrar um valor padrão quando nulo (foi o que fiz), mas nem sempre temos auxilio de ferramentas.

Referencia:
http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html#function_ifnull

Anúncios

2 ideias sobre “MySQL Trabalhando com NULL

  1. Raphael Leal

    Olá Marcos, parabéns pelo blog é de grande satisfação postar um comentário, apesar de ser quase impossível agregar algo mais em seus post’s, porém gostaria de deixar minha contribuição em relação ao comando Between. Recentemente ouvi dizer que a utilização desse comando pode causa uma queda de desempenho em BD com mais de milhoes de registreos. Rss.. Sabendo que para o BD esse comando será traduzido para p.codigo >= ‘’ and p.codigo <= ‘9999999999’. Já ouviu falar algo sobre?

    Um grande Abraço
    Big Head.

    Resposta
    1. Marcos Vidolin Autor do post

      Olá Raphael,
      Já agregou bastante levantando esta bola!

      Como você sabe, não sou especialista em banco de dados, mas levando em consideração apenas a lógica envolvida numa consulta que faz uso do between numa tabela com milhões de registros (principalmente usando uma clausula tão abrangente como foi proposta no post) a consulta não será performática. Ou seja, quanto mais especifica e simples for a sua clausula where mais performática será a busca.
      Uma busca de um registro pelo ID, pode ser um exemplo de uma busca performática.

      Espero ter entendido sua pergunta!
      Se souber de alguma alternativa ou boa prática para tratar esse caso, compartilha para aprendermos.

      Obrigado brother.
      []’s

      Resposta

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s