+7

Consultas complexas utilizando processamento condicional no MySql.

criado por Emanuel Fonseca em 18/12/2003 10:33am
Em determinados momentos de nossa carreira, a necessidade nos leva a quebrar certos vícios habituais, como as boas e velhas consultas à banco de dados. Acredito que a grande maioria, com o tempo adquire este mau hábito e assim tornando mais difícil sua evolução pessoal. Há algumas semanas me deparei com um sistema que realmente me consumiu dias a procura de uma solução eficaz e definitiva. Tomaremos esta como exemplo, para que de alguma forma ajudar todos aqueles que se depararem com este tipo de problema.


Abaixo apresento a solução que encontrei e descrevo sua utilização e sintaxe.

SELECT *,IF(expiraano = '$ano' and expirames >= '$mes' and expiradia >= '$dia', 0, 1) as presente, IF(expiraano > '$ano', 2,3) as futuro from clientes having presente = '0' or futuro = '2'


Eu precisava fazer um relatório de clientes ativos. Eu tinha 03 campos no BD: Um que equivale ao ano de vencimento, outro que equivalia ao mês de vencimento e outro que equivalia ao dia de vencimento. Basicamente iniciei pelo mais fácil, que era comparar valores através de where. Porém tornou-se meramente impossível, adotar este tipo de comparação, pois sempre retornaria registros de forma não pertinente ao resultado que necessitava. A minha primeira tentativa (vicio) foi utilizar o exemplo:

SELECT * FROM clientes where expiraano >= $ano and expirames >= $mes and expiradia = $dia

Esta clausula retornava valores, porém com alguns erros. Ela listava apenas o mês seguinte (no caso de se tratar do mês 12) e mesmo assim os dias não conferiam, tornando nossos resultados totalmente infiéis à realidade. E qual a solução a ser aplicada, diante desta incógnita? Seria fazer uma consulta anterior e utilizar processamento condicional para exibir os dados. Certo! Realmente funcionaria, porém havia um outro problema: A paginação dos dados. Então fui à caça de soluções alternativas, e comecei a vasculhar a documentação do banco de dados (que também não ajuda muito, já que é bem simplória em termos de exemplos). Já conhecia esta implementação para controle de fluxo, porém não sabia que poderia aplica - lá em conjunto com consultas em tabelas (como disse a documentação é pobre no sentido). Depois de inúmeras tentativas, cheguei ao resultado desejado conforme descreverei abaixo:

SELECT * (Até aqui esta tudo bem, não muda em nada o select habitual)

,IF(expiraano = '$ano' and expirames >= '$mes' and expiradia >= '$dia', 0, 1) as presente,

Aqui adotamos então a primeira avaliação condicional. Se vocês notarem a virgula antes do "IF", notarão que nosso controle de fluxo toma forma de campo. Dentro do "IF" fazemos comparações até que habituais, porém esta é a parte mais importante da nossa consulta. Notem que a estrutura do "IF" é dividida em 3 partes: IF(expression,then,else). Onde o que está antes da primeira vírgula, caso retorne verdadeiro (true) esse campo tomará o valor especificado e/ou expressão que esta após a primeira vírgula (0). Caso nossa expressão antes da primeira vírgula retorne false , nosso campo tomará o valor e/ou expressão que esta após a segunda vírgula (1). Por fim criaremos um alias para este novo campo , através de "as nomedocampo". Se não tivermos este cuidado nosso campo terá o mesmo nome que a condicional, ou seja, terá o nome "IF(expiraano = '$ano' and expirames >= '$mes' and expiradia >= '$dia', 0, 1)".

Agora vamos a segunda condicional:

,IF(expiraano > '$ano', 2,3) as futuro

Na segunda avaliação procedemos com outra comparação, e como foi visto anteriormente se esta for verdadeira retornará o campo tomará como valor o que segue após a primeira virgula e se for falsa terá como valor o que segue após a segunda virgula. Criamos um alias para nosso novo campo no Banco de dados.

Comentários:

Mostrando 1 - 10 de 21 comentários
Eric disse:
Interessante...
Esse é o problema quando pegamos um sistema feito.
A estrutura da banco de dados nao é muito boa... Muito bom!!


http://www.mundodaweb.com.br
22/07/2008 7:19pm (~15 anos atrás)

fccd disse:
Que legal esse artigo...


Show
12/01/2008 10:20am (~16 anos atrás)

NuNuNO disse:
Muito menos matematico, se você tem três campos para UMA data... Por que não usar o concat na hora de comparar?

Por exemplo:

select * from clinetes concat(anoexpira,'-',$mesexpira,'-',diaexpira) >= curdate()

Testei no mySql 5.0, talvez em versões anteriores você precise usar o cast junto com o concat...

Grande Abraço
=NuNuNO==
( Que adora usar o IF em consultas, mas usa de outras formas... )

PS: É muito recomendado utilizar o tipo DATE do mySQL ao inves de trÊs campos integer...
19/01/2007 3:28pm (~17 anos atrás)

Cara, esse artigo veio em boa hora... Queria fazer a mesma coisa que você fez.
Aqui deu tudo certo.

Abraços
17/07/2005 6:35pm (~19 anos atrás)

Pega os 3 campos e concatena com CONCAT(), depois usa o comando DATE() para o mysql considerar e formatar como uma data, depois é só comparar com a data atual CURDATE().

SELECT * FROM clientes
WHERE DATE( CONCAT( ano , '-' , mes , '-' , dia ) ) > CURDATE();

Isso vai retornar todos os clientes que expiram de amanhã para frente...

Se quiser com mais tempo
> CURDATE() + INTERVAL 1 MONTH

etc...
15/07/2005 7:23am (~19 anos atrás)

Aproveitando a deixa, não sei se estou usando corretamente o espaço, mas comumente me deparo com o seguinte problema: uma tabela de clientes, com um bit indicando se é pessoa física ou jurídica; outras 2 tabelas (uma para PF outra para PJ) com os dados específicos de cada uma.

Existe alguma maneira de indicar no operador condicional, para mais de um registro no retorno, dizer para qual tabela o MySQL deve fazer o join para cada registro?
27/01/2004 7:20am (~20 anos atrás)

Cléver, acho que para esse caso seria melhor usar a função IFNULL(expr1,expr2), que retorna a expressão 1 se ela não for NULL; se for, retorna EXPR2.

Outro estrutura bem útil é o CASE, primeiro tópico da página de funções de controle de fluxo na página de ajuda do MySQL.
27/01/2004 7:18am (~20 anos atrás)

Cléver Anjos disse:
Uma utilização interessante é trazer algum valor de colunas que admitem NULL.

Exemplo :

SELECT nome, IF ( endereco is null, "Endereco nao preenchido", endereco) FROM enderecos ORDER BY nome

19/01/2004 7:35am (~20 anos atrás)

O intuito do artigo é a syntax do if.
04/01/2004 3:05pm (~20 anos atrás)

A melhor solução é concatenar as datas ano+mes+dia, assim você terá mais facilidade para comparar e não vai condicionar a sua instrução. O próprio MySql organiza as datas desta forma.
31/12/2003 8:00am (~20 anos atrás)

Novo Comentário:

(Você pode usar tags como <b>, <i> ou <code>. URLs serão convertidas para links automaticamente.)