Separar linhas em colunas postgresql

PostgreSQL

07/07/2014

Bom dia amigos,
estou com dificuldades no postgre SQL em separar linhas em colunas, por exemplo:

Tenho os seguintes dados:

Data | Máquina | Qtd
01/07/2014 | serra 1 | 12
01/07/2014 | serra 2 | 18
02/07/2014 | serra 1 | 14
02/07/2014 | serra 2 | 15

Quero apresentar da seguinte forma:

Máquina | 01/07/2014 | 02/07/2014
serra 1 | 12 | 14
serra 2 | 18 | 15

e assim sucessivamente conforme for abastecendo o banco com mais datas...

Grato.
Renan Maia

Renan Maia

Curtidas 0

Melhor post

Ronaldo Lanhellas

Ronaldo Lanhellas

07/07/2014

Bom, criei uma função com base nos dados que você me passou. A forma que pensei foi mostrar através do RAISE NOTICE a formatação que você deseja, mas fique a vontade para mudar se precisar.

CREATE OR REPLACE FUNCTION public.func_dados_serra (
)
RETURNS void AS
$body$
DECLARE 
r						    RECORD;
p							RECORD;
q							RECORD;
qtd_aux						integer;
cabecalho	 				text;
linha						text;
BEGIN 
   
    cabecalho = 'MAQUINA';    
	
	FOR r IN SELECT data FROM dados_serra GROUP BY data ORDER BY data ASC
	LOOP
	cabecalho = cabecalho || ' | ' || r.data;         
	END LOOP;   
    
    RAISE NOTICE '%',cabecalho;
    
     FOR p IN SELECT maquina FROM dados_serra GROUP BY maquina
     LOOP   
        linha = p.maquina;
		
        FOR q IN SELECT qtd FROM dados_serra WHERE maquina = p.maquina ORDER BY data ASC        
        LOOP 
         linha = linha || ' | ' || q.qtd;
        END LOOP;
        
        RAISE NOTICE '%',linha;
     END LOOP;
END;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100;


Testei e a saída foi essa:

NOTICE:  MAQUINA | 2014-07-01 | 2014-07-02
NOTICE:  serra 1 | 12 | 14
NOTICE:  serra 2 | 18 | 15
Total query runtime: 33 ms.
1 row retrieved.
GOSTEI 1

Mais Respostas

Ronaldo Lanhellas

Ronaldo Lanhellas

07/07/2014

No seu caso notei que as colunas são dinâmicas, pois podem existir diversas datas e você não tem como saber quantas são. A melhor solução seria criar uma função que montasse o seu SQL de forma dinâmica.
GOSTEI 0
Renan Maia

Renan Maia

07/07/2014

Obrigado pela resposta Ronaldo,
Porém sou novo na área de programação etc... poderia me dar um exemplo de como fazer isso?

Mais uma vez obrigado.
GOSTEI 0
Fabiano Carvalho

Fabiano Carvalho

07/07/2014

Pesquise por pivot ou crosstab, se voce informar as datas manualmente irá fazer o que voce deseja, mas é aconselhado a fazer a função como foi indicado.
Não posso te ajudar tanto pois não trabalho com postgre, mas pela pesquisa rápida encontrei algumas soluções.
GOSTEI 0
Ronaldo Lanhellas

Ronaldo Lanhellas

07/07/2014

Vou preparar um exemplo e já lhe repasso.
GOSTEI 0
Renan Maia

Renan Maia

07/07/2014

Ótimo Ronaldo, muito obrigado pela ajuda, ainda não testei mas creio que irá funcionar.
Fabiano, obrigado pela dica.


Att
Renan.
GOSTEI 0
Ronaldo Lanhellas

Ronaldo Lanhellas

07/07/2014

Bom, funcionar funciona, partindo da estrutura de tabela que você passou no início do post, só não sei se é exatamente o que você precisa. De qualquer forma, já é um começo e você pode adaptar para sua necessidade.
GOSTEI 0
Renan Maia

Renan Maia

07/07/2014

Fiz todos os teste agora a tarde, porem achei a solução para meu problema, o FastReport possui o objeto Cross Tab, que pode ser ordenado de forma visual a tabela.
Portanto, se alguém tiver o mesmo problema, o fast possui uma solução fácil.
GOSTEI 0
Ronaldo Lanhellas

Ronaldo Lanhellas

07/07/2014

Bom, de fato usar uma IDE para construção de relatório simplifica tudo, mas como você não exemplificou para que precisava disso, não tinha como opinar.
GOSTEI 0
Renan Maia

Renan Maia

07/07/2014

Bom, eu precisava extrair do banco de dados e apresentar de alguma forma, apos quebrar a cabeça a tarde toda é que veio a ideia de montar um gerador de relatórios pra simplificar tudo :).

Mas agora estou com um novo problema, tenho a seguinte linha de comando na Query/postgres, que seleciona a tabela de tempo parado de cada máquina e apresenta numa query...

select pa.ds_parada, sum(ap.qtd_minutoparado) as minutos
from apontador ap
inner join paradas pa on pa.seq = ap.cd_parada
where ap.cd_horas = 11 and ap.dt_apontador between '01/07/2014' and '09/07/2014'
group by pa.ds_parada

.... que me traz os seguintes dados no postgres...

"RETRABALHO";250
"TROCA DE FERRAMENTAS/SETUP";2040
"FALTA DE PROGRAMACAO";75
"FALHA MECANICA";135
"CAFÉ/ALIMENTAÇÃO";90
"FALHA ELETRICA";1310
"FALTA DE EXAUSTAO";175
"FALTA DE MATERIA PRIMA";1100
"REUNIAO/TREINAMENTO";60
"FALTA DE AR COMPRIMIDO";135
"FALTA DE COLABORADOR";180
"FALTA DE EMPILHADEIRA";60

...existe aluma função especifica no POSTGRES para converter os valores que estão em minutos para horas, pois só dividir por exemplo os 250 minutos da primeira linha por 60 não resolve o problema.

Grato.
GOSTEI 0
Ronaldo Lanhellas

Ronaldo Lanhellas

07/07/2014

Porque não resolve o problema ? Qual o tipo de dado da sua coluna ?

Pois se fizer isso:

SELECT 250/4; 


Verá que o resultado = 4, minutos.
GOSTEI 0
Ronaldo Lanhellas

Ronaldo Lanhellas

07/07/2014

Porque não resolve o problema ? Qual o tipo de dado da sua coluna ?

Pois se fizer isso:

SELECT 250/4; 


Verá que o resultado = 4, minutos.


Desculpe, corrigindo o codigo acima:

SELECT 250/60; 
GOSTEI 0
Renan Maia

Renan Maia

07/07/2014

A coluna minutos é do tipo integer, logo se eu dividir 250 por 60 = 4,16 horas, até ai tudo bem, sei que são 4 horas e pra eu saber o valor do ,16 é tenho que multiplicar novamente por 60 pra saber quantos minutos representam 0,16. O problema é que não sei como pegar somente o ,16 e multiplica por 60.
GOSTEI 0
Ronaldo Lanhellas

Ronaldo Lanhellas

07/07/2014

Tente assim:

select (250/60) as hora, (250.0/60.0) - (250/60) as minutos;
GOSTEI 0
Renan Maia

Renan Maia

07/07/2014

Ronaldo, deu certo assim. Retornou 4 horas, 10 minutos.

#Código
select (250/60) as hora, ((250.0/60.0) - (250/60))*60 as minutos;
GOSTEI 0
Ronaldo Lanhellas

Ronaldo Lanhellas

07/07/2014

Ótimo, que bom que deu certo.
GOSTEI 0
Renan Maia

Renan Maia

07/07/2014

Portanto, se alguém precisar do codigo que converta minutos em horas (horas serão no formato string) segue abaixo...

select pa.ds_parada, coalesce(cast( (sum(ap.qtd_minutoparado)/60) as varchar),'') || (':') || 
coalesce(cast(trunc(((sum(ap.qtd_minutoparado)/60.0 - (sum(ap.qtd_minutoparado)/60))*60)) as varchar), '') as horas, sum(ap.qtd_minutoparado) as minutos
from apontador ap
inner join paradas pa on pa.seq = ap.cd_parada
where ap.cd_horas = 11 and ap.dt_apontador between '01/07/2014' and '08/07/2014' 
group by pa.ds_parada
order by minutos desc


retornou o seguinte valor...

"TROCA DE FERRAMENTAS/SETUP31:0";1860
"FALHA ELETRICA";"21:49";1310
"FALTA DE MATERIA PRIMA";"18:19";1100
"RETRABALHO";"4:10";250
"FALTA DE EXAUSTAO";"2:55";175
"FALTA DE AR COMPRIMIDO";"2:15";135
"FALHA MECANICA";"2:15";135
"FALTA DE COLABORADOR";"2:0";120
"CAFÉ/ALIMENTAÇÃO";"1:30";90
"REUNIAO/TREINAMENTO";"1:0";60
"FALTA DE EMPILHADEIRA";"1:0";60
"FALTA DE PROGRAMACAO";"0:45";45
GOSTEI 0
Renan Maia

Renan Maia

07/07/2014

Complementando, primeira coluna é a descrição (varchar), segunda coluna é as horas (varchar) e a terceira coluna são os minutos (int);

Abraço.
GOSTEI 0
POSTAR