Order a table by grouped columns
Wednesday September 1st, 2010 07:53 PM
Para os exemplos abaixo criamos uma tabela pessoas e inserimos os registros abaixo. O código SQL para criar a tabela e inserir os registros seguem abaixo:
# criando a tabela pessoas create table pessoas ( id bigint(20) unsigned not null auto_increment, str_nome varchar(50) not null, int_altura int(5) not null, flo_peso float not null, int_felicidade int(1) not null, primary key (id) ); # inserindo os registros insert into pessoas values ( '1','Thiago','184','85.2','9'); insert into pessoas values ( '2','Matheus','175','90','8'); insert into pessoas values ( '3','Guilherme','188','78','6'); insert into pessoas values ( '4','Rafael','177','92','5');
Todos sabem que é possível ordenar uma consulta de banco de dados MySQL por multiplas colunas utilizando uma por vez:
select * from pessoas order by int_altura desc # primeiro ordenamos pela altura ,flo_peso desc # quando a altura for igual ordenamos pelo peso ;
O que acontece de fato, é que o primeiro valor é o utilizado para a ordenação, em caso de empate na ordeção a segunda coluna é utilizada e assim por diante. Mas e quando a necessidade é que as duas ou mais colunas tenham o mesmo peso e sejam levadas em consideração ao mesmo tempo? Para resolver esta demanda criei uma pequena função em MySQL que pode ajudar nesta tarefa.
# Criando a funcao # autor: Tatto <mysql><tattodecastro.com> delimiter $$ ; drop function if exists fn_ordena_multiplos_campos $$ create function fn_ordena_multiplos_campos( fn_in_int_altura int( 5 ) ,fn_in_flo_peso float ,fn_in_int_felicidade int( 1 ) ) returns float deterministic begin # Tratamento para a primeira interação, onde salvamos os valores iniciais para as comparações futuras. if isnull(@temporary_variable_altura_sdsdfe3) = true then set @temporary_variable_altura_sdsdfe3 = fn_in_int_altura; set @temporary_variable_peso_sdsdfe3 = fn_in_flo_peso; set @temporary_variable_felicidade_sdsdfe3 = fn_in_int_felicidade; return 1; else # Todos os retornos subsequentes são relativos ao primeiro. return ( fn_in_int_altura/@temporary_variable_altura_sdsdfe3 + fn_in_flo_peso/@temporary_variable_peso_sdsdfe3 + fn_in_int_felicidade/@temporary_variable_felicidade_sdsdfe3 )/3; end if; end $$ delimiter ; $$ select * from pessoas order by # Ordenando pela função criada. fn_ordena_multiplos_campos(int_altura, flo_peso, int_felicidade) desc ;
Outras soluções como a criação de uma nova coluna que tenha os valores das colunas com as determinadas valências podem ser um solução. Só que para garantir a consistência dos dados a criação de um trigger ou outro componente de banco teria que ser feito. Uma terceira solução seria utilizar três vezes a consulta na mesma tabela criando uma coluna de valência. Só que a utilização da função demonstrou uma melhor performance.
Qualquer dúvida, entre em contato.
Um abraço, Tatto