Como transformar vários registros em apenas um convertendo os dados de um campo em nome de colunas?
Considerando esta tabela PONTUACAO com os seguintes campos e valores "fictícios"
TIMEF ANO PONTOS
FLAMENGO 2002 16
FLAMENGO 2003 18
FLAMENGO 2004 21
PALMEIRAS 2002 15
PALMEIRAS 2003 17
PALMEIRAS 2004 14
INTER 2002 18
INTER 2003 17
INTER 2004 20
SAO PAULO 2002 17
SAO PAULO 2003 19
SAO PAULO 2004 19
como poderia usando SQL selecionar de forma que teria apenas um registro distinto para cada time, e que cada ano fosse convertido em nome de coluna com os respectivos pontos
Exemplo de resultado desejado:
TIMEF 2002 2003 2004
FLAMENGO 16 18 21
PALMEIRAS 15 17 14
INTER 18 17 20
SAO PAULO 17 19 19
Agradeço por todas dicas, exemplos, trechos de códigos SQL, outros exemplos de SQL com o mesmo propósito, etc
Delmar
TIMEF ANO PONTOS
FLAMENGO 2002 16
FLAMENGO 2003 18
FLAMENGO 2004 21
PALMEIRAS 2002 15
PALMEIRAS 2003 17
PALMEIRAS 2004 14
INTER 2002 18
INTER 2003 17
INTER 2004 20
SAO PAULO 2002 17
SAO PAULO 2003 19
SAO PAULO 2004 19
como poderia usando SQL selecionar de forma que teria apenas um registro distinto para cada time, e que cada ano fosse convertido em nome de coluna com os respectivos pontos
Exemplo de resultado desejado:
TIMEF 2002 2003 2004
FLAMENGO 16 18 21
PALMEIRAS 15 17 14
INTER 18 17 20
SAO PAULO 17 19 19
Agradeço por todas dicas, exemplos, trechos de códigos SQL, outros exemplos de SQL com o mesmo propósito, etc
Delmar
Delmar Observação)
Curtidas 0
Respostas
Marcelo Cavalcanti
23/03/2010
O que acha de tratar o resultado no código da aplicativo, ao invés de usar o SQL? Somente uma dica.
Sds,
Marcelo Rezende Cavalcanti
--------------------------------------------------------------------
www.swg2.com.br (Transformando suas informações em dados gerenciais)
--------------------------------------------------------------------
www.swg2.com.br (Transformando suas informações em dados gerenciais)
GOSTEI 0
Delmar Observação)
23/03/2010
Olá Marcelo
Sim, já pensei em tratar via código onde eu faria uma sql para pegar os anos distintos para criar em tempo de execução as colunas em uma grid, uma outra sql para pegar os times distintos e adicionar em uma grid as n linhas e, no terceiro passo, iria percorrer todos os registros da minha tabela (consulta) e localizar na grid o registro/coluna e add o valor.
Mas o objetivo é exatamente tentar desvendar uma forma de fazer isso via SQL para simplificar este trabalho. Por isso postei aí para ver se levanto algumas ideias.
De qualquer forma obrigado
Sim, já pensei em tratar via código onde eu faria uma sql para pegar os anos distintos para criar em tempo de execução as colunas em uma grid, uma outra sql para pegar os times distintos e adicionar em uma grid as n linhas e, no terceiro passo, iria percorrer todos os registros da minha tabela (consulta) e localizar na grid o registro/coluna e add o valor.
Mas o objetivo é exatamente tentar desvendar uma forma de fazer isso via SQL para simplificar este trabalho. Por isso postei aí para ver se levanto algumas ideias.
De qualquer forma obrigado
GOSTEI 0
Thiago Santana
23/03/2010
Delmar vc deverá criar uma tabela com os respectivos campos e colunas!
Assim irá ter as colunas TimeF, 2002, 2003 e 2004, mas tbem deverá ter chaves estrangeiras. Passando os valores comparando. Mas acho que vc deverá utilizar uma Procedure e não apenas um SQL!
Tenta postar algo do SQL que vc está tentando fazer! Assim teremos mais facilidade em tentarmos resolver esta duvida!
Espero ter ajudado.... AbraçoO
Espero ter ajudado.... AbraçoO
GOSTEI 0
Emerson Nascimento
23/03/2010
você pode fazer via stored procedure ou pode fazer como nosso colega fez neste tópico.
GOSTEI 0
Delmar Observação)
23/03/2010
ThiiaGuinho
País: Brasil
Estado: SE
Cidade: Aracaju
Mensagens: 267
Usuário DevMaster
#ID: 130897 Postado em: 23/3/2010 2:27:43 PM
Delmar vc deverá criar uma tabela com os respectivos campos e colunas! Assim irá ter as colunas TimeF, 2002, 2003 e 2004, mas tbem deverá ter chaves estrangeiras. Passando os valores comparando. Mas acho que vc deverá utilizar uma Procedure e não apenas um SQL! Tenta postar algo do SQL que vc está tentando fazer! Assim teremos mais facilidade em tentarmos resolver esta duvida!
Espero ter ajudado.... AbraçoO
Olá ThiiaGuinho
Esqueci de dizer, as colunas são registros porque as colunas não podem ser fixas neste caso de uso.
Neste exemplo as colunas deveriam ser anos, mas como nunca sei quais são os anos não posso fixá-los como colunas em minha tabela física.
Por isso acabo tendo vários registros.
Mas a discussão tá boa, to gostando da participação, das ideias e da iniciativa de cada um.
Estive tentando algo com subconsultas, como abaixo:
select timef,
(select pontos from pontuacao where timef=p.timef and ano=2002) as ano_2002,
(select pontos from pontuacao where timef=p.timef and ano=2003) as ano_2003,
(select pontos from pontuacao where timef=p.timef and ano=2004) as ano_2004
from
(select distinct(timef) from pontuacao) p
Porém, no exemplo, iria usar uma sql auxiliar para iterar os anos distintos para montar a parte que seleciona as colunas.
Só que não gosto desta sql, porque ela tem muitos select nos campos, o que poderia ficar lento.
Enquanto isso sigo estudando e pesquisando algo com crosstab para firebird
País: Brasil
Estado: SE
Cidade: Aracaju
Mensagens: 267
Usuário DevMaster
#ID: 130897 Postado em: 23/3/2010 2:27:43 PM
Delmar vc deverá criar uma tabela com os respectivos campos e colunas! Assim irá ter as colunas TimeF, 2002, 2003 e 2004, mas tbem deverá ter chaves estrangeiras. Passando os valores comparando. Mas acho que vc deverá utilizar uma Procedure e não apenas um SQL! Tenta postar algo do SQL que vc está tentando fazer! Assim teremos mais facilidade em tentarmos resolver esta duvida!
Espero ter ajudado.... AbraçoO
Olá ThiiaGuinho
Esqueci de dizer, as colunas são registros porque as colunas não podem ser fixas neste caso de uso.
Neste exemplo as colunas deveriam ser anos, mas como nunca sei quais são os anos não posso fixá-los como colunas em minha tabela física.
Por isso acabo tendo vários registros.
Mas a discussão tá boa, to gostando da participação, das ideias e da iniciativa de cada um.
Estive tentando algo com subconsultas, como abaixo:
select timef,
(select pontos from pontuacao where timef=p.timef and ano=2002) as ano_2002,
(select pontos from pontuacao where timef=p.timef and ano=2003) as ano_2003,
(select pontos from pontuacao where timef=p.timef and ano=2004) as ano_2004
from
(select distinct(timef) from pontuacao) p
Porém, no exemplo, iria usar uma sql auxiliar para iterar os anos distintos para montar a parte que seleciona as colunas.
Só que não gosto desta sql, porque ela tem muitos select nos campos, o que poderia ficar lento.
Enquanto isso sigo estudando e pesquisando algo com crosstab para firebird
GOSTEI 0
Thiago Santana
23/03/2010
É uma boa idéia CrossTab, mas acho que com uma Procedure já que vc está utilizando o Firebird terá mais sucesso!
De qualquer maneira... Boa Sorte!
Espero ter ajudado!
AbraçoO
Espero ter ajudado!
AbraçoO
GOSTEI 0
Emerson Nascimento
23/03/2010
no exemplo passado no tópico https://www.devmedia.com.br/forum/viewtopic.asp?id=62204 não há subselects. somente condicionais com case.
GOSTEI 0
Delmar Observação)
23/03/2010
Olá Emerson
Ambos os códigos abaixo funcionam, sendo bem melhor que os selects nos campos. Mas tenho que usar uma função de agregação, como o max ou o min. Neste caso dá certo, porque não há repetição de registro dentro do mesmo time e ano (campo único timef+ano), ou seja, eu terei apenas um valor e fazer max ou min sobre um único valor resulta o próprio valor.
SELECT TIMEF,
MAX(CASE WHEN ANO = '2002' THEN PONTOS END) AS ANO2002,
MAX(CASE WHEN ANO = '2003' THEN PONTOS END) AS ANO2003,
MAX(CASE WHEN ANO = '2004' THEN PONTOS END) AS ANO2004
FROM PONTUACAO
GROUP BY TIMEF
SELECT TIMEF,
MIN(CASE WHEN ANO = '2002' THEN PONTOS END) AS ANO2002,
MIN(CASE WHEN ANO = '2003' THEN PONTOS END) AS ANO2003,
MIN(CASE WHEN ANO = '2004' THEN PONTOS END) AS ANO2004
FROM PONTUACAO
GROUP BY TIMEF
E agora eu posso usar uma query auxiliar para iterar e formar as colunas dinamicamente como eu vinha pensando.
A lógica aí é agrupar os registros e depois usar o case e uma query auxiliar, para desagrupar em colunas.
Mas se alguém tiver outra ideia para evitar o uso da função max/min, manda aí que vamos estudar com carinho.
Obrigado Emerson e demais colegas, pois somadas as preciosas dicas, estou caminhando ruma a solução que estava idealizando e que me agrada mais.
Ambos os códigos abaixo funcionam, sendo bem melhor que os selects nos campos. Mas tenho que usar uma função de agregação, como o max ou o min. Neste caso dá certo, porque não há repetição de registro dentro do mesmo time e ano (campo único timef+ano), ou seja, eu terei apenas um valor e fazer max ou min sobre um único valor resulta o próprio valor.
SELECT TIMEF,
MAX(CASE WHEN ANO = '2002' THEN PONTOS END) AS ANO2002,
MAX(CASE WHEN ANO = '2003' THEN PONTOS END) AS ANO2003,
MAX(CASE WHEN ANO = '2004' THEN PONTOS END) AS ANO2004
FROM PONTUACAO
GROUP BY TIMEF
SELECT TIMEF,
MIN(CASE WHEN ANO = '2002' THEN PONTOS END) AS ANO2002,
MIN(CASE WHEN ANO = '2003' THEN PONTOS END) AS ANO2003,
MIN(CASE WHEN ANO = '2004' THEN PONTOS END) AS ANO2004
FROM PONTUACAO
GROUP BY TIMEF
E agora eu posso usar uma query auxiliar para iterar e formar as colunas dinamicamente como eu vinha pensando.
A lógica aí é agrupar os registros e depois usar o case e uma query auxiliar, para desagrupar em colunas.
Mas se alguém tiver outra ideia para evitar o uso da função max/min, manda aí que vamos estudar com carinho.
Obrigado Emerson e demais colegas, pois somadas as preciosas dicas, estou caminhando ruma a solução que estava idealizando e que me agrada mais.
GOSTEI 0
Delmar Observação)
23/03/2010
Como esqueci de informar nos outros posts, estou voltando para informar que não desejo usar SP, quero achar uma solução nativa SQL fora do DB que dispense o uso de SP.
É isso aí galera. Amanhã continuo as buscas e testes sobre uma possível melhoria no código e na otimização.
É isso aí galera. Amanhã continuo as buscas e testes sobre uma possível melhoria no código e na otimização.
GOSTEI 0
Edinei Colli
23/03/2010
Para fazer isso com um simples select terá que utilizar os anos de forma fixa criando alias para as colunas, pelo modelo que passou, os anos podem variar e não é bom utilizar nada fixo.
Outro detalhe, se for imprimir um relatório em que existam muitos anos a serem listados, provavelmente alguns ficarão de fora da pagina.
Talvez o select abaixo seja uma solução prática e somente com duas colunas:
SELECT
TIMEF
,ano || ': ' || sum(PONTOS)|| ' pontos.' as "Ano/Ponto(s)"
FROM PONTUACAO
GROUP BY TIMEF, ANO
ORDER BY ANO, TIMEF;
Outro detalhe que devemos levar em conta para tentar a solução para esse problema é qual a chave da sua tabela pontuacao?Será gravado 1 ou mais registros para cada clube em 1 ano?Quantos anos serão armazenados?Entre outras perguntas que poderiam auxiliar.
Outro detalhe, se for imprimir um relatório em que existam muitos anos a serem listados, provavelmente alguns ficarão de fora da pagina.
Talvez o select abaixo seja uma solução prática e somente com duas colunas:
SELECT
TIMEF
,ano || ': ' || sum(PONTOS)|| ' pontos.' as "Ano/Ponto(s)"
FROM PONTUACAO
GROUP BY TIMEF, ANO
ORDER BY ANO, TIMEF;
Outro detalhe que devemos levar em conta para tentar a solução para esse problema é qual a chave da sua tabela pontuacao?Será gravado 1 ou mais registros para cada clube em 1 ano?Quantos anos serão armazenados?Entre outras perguntas que poderiam auxiliar.
GOSTEI 0