Oi! Seja bem-vindo!
Hoje veremos como fazer PIVOT com COLUNAS DINÂMICAS no SQL Server. Com essa técnica NINJA, você não precisará alterar querys quando mudarem os dados usados no PIVOT.
O que é PIVOT com COLUNAS dinâmicas?
No vídeo da última semana [https://youtu.be/mvClicAwyek] mostrei o comando PIVOT, que serve para transformar linhas em colunas no SQL Server, melhorando espetacularmente o visual de relatórios.
Se você ainda não leu o artigo da semana passada e/ou não viu o vídeo, te convido a assistir, pois nosso trabalho dessa semana é uma continuação dele.
De qualquer forma, a maior utilidade do PIVOT com colunas dinâmicas, é evitar que precisemos alterar nossos sistemas e consultas SELECT a cada vez que mudam dados no banco de dados.
Como fazer PIVOT com COLUNAS DINÂMICAS
Abaixo o script que utilizei no vídeo:
------------------------------------------------------------------ -- PIVOT: Transposição (linhas para colunas DINAMICAMENTE) ------------------------------------------------------------------ -------------------------------------------------- -- Banco de dados para nosso teste -------------------------------------------------- -- Banco de testes use master if db_id('curso') is not null drop database curso go create database curso go use curso go create table colaboradores ( id smallint identity(1,1) primary key, nm varchar(100) not null, ) insert into colaboradores values ('Abismail do Rosário'), ('Josemar Pinto Godinho'), ('Francisco Sanguessuga'), ('Rolando da Rocha'), ('Chaves Rosembaum'), ('Necrotério Silveira'), ('Navegador da Luz') create table produtos ( id smallint identity(1,1) primary key, nm varchar(100), vl decimal(10,2), ic_ativo bit not null default (1) ) insert produtos (nm, vl) values ('Mouse Gammer 25 botões', 200), ('Teclado Gammer 350 teclas', 300), ('Monitor 32 Pol Full HD', 1000), ('RAM DDR4 4GB Powerturbo', 500), ('CPU Nasa 10Ghz', 2000), ('HD SSD 1TB', 2000) create table vendas ( id int not null identity(1, 1) primary key, dt datetime not null, id_produto smallint not null foreign key references produtos(id), id_vendedor smallint foreign key references colaboradores(id), qt int check (qt > 0), vl_unitario decimal (10,2), vl_venda as qt * vl_unitario ) ;with cte_seq as ( select 1 as nr_cont union all select nr_cont + 1 from cte_seq where nr_cont < 10000) insert into vendas (dt, id_produto, id_vendedor, qt, vl_unitario) select dateadd(day, -(abs(checksum(newid())) % 1825), getdate()) dt, produto.id, colaborador.id, 1 + (abs(checksum(newid())) % 15) nr_quantidade, produto.vl vl_unitario from cte_seq left join (select top 1 id, vl from produtos order by newid()) produto on 1=1 left join (select top 1 id from colaboradores order by newid()) colaborador on 1=1 option (maxrecursion 0) go -------------------------------------------------- -- Pivot padrão (com colunas fixas) -------------------------------------------------- -- Anos em colunas: select * from ( select year(dt) as Ano, c.nm as Colaborador, sum(vl_venda) as Valor from vendas join colaboradores c on c.id = vendas.id_vendedor group by c.nm, year(dt) ) em_linha pivot (sum(valor) for ano in ([2012], [2013], [2014], [2015], [2016], [2017])) em_colunas order by 1 go -- Colaboradores em colunas: select * from ( select year(dt) as Ano, c.nm as Colaborador, sum(vl_venda) as Valor from vendas join colaboradores c on c.id = vendas.id_vendedor group by c.nm, year(dt) ) em_linha pivot (sum(valor) for colaborador in ([Abismail do Rosário], [Chaves Rosembaum], [Francisco Sanguessuga])) em_colunas order by 1 go -------------------------------------------------- -- Pivot ninja - colunas dinâmicas -------------------------------------------------- -- Anos em colunas dinâmicas declare @colunas_pivot as nvarchar(max), @comando_sql as nvarchar(max) set @colunas_pivot = stuff(( select distinct ',' + quotename(year(dt)) from vendas for xml path('') ), 1, 1, '') print @colunas_pivot set @comando_sql = ' select * from ( select year(dt) as Ano, nm as Colaborador, sum(vl_venda) as Valor from vendas join colaboradores c on c.id = vendas.id_vendedor group by nm, year(dt) ) em_linha pivot (sum(valor) for ano in (' + @colunas_pivot + ')) em_colunas order by 1' print @comando_sql execute(@comando_sql) go -- Colaboradores em colunas dinâmicas declare @colunas_pivot as nvarchar(max), @comando_sql as nvarchar(max) set @colunas_pivot = stuff((select distinct ',' + quotename(nm) from colaboradores for xml path('')), 1, 1, '') print @colunas_pivot set @comando_sql = ' select * from ( select nm as Colaborador, year(dt) as Ano, sum(vl_venda) as Valor from vendas join colaboradores c on c.id = vendas.id_vendedor group by nm, dt ) em_linha pivot (sum(valor) for colaborador in (' + @colunas_pivot + ')) em_colunas order by 1' print @comando_sql execute(@comando_sql) -------------------------------------------------- -- Excluindo dados de teste -------------------------------------------------- use master drop database curso
CONCLUSÃO
Particularmente não sou chegado a execuções indiretas de código por serem menos performáticas e mais difíceis de dar manutenção. Mas, em casos como esse, essa técnica salva a pátria, não?
Espero que tenha gostado do artigo, nos vemos no próximo!
Abraço do seu amigo Josué 🙂
Bom dia!
Quando adaptei a dica ninja não deu certo.
O que fiz de errado ?
declare @colunas_pivot as nvarchar(max), @comando_sql as nvarchar(max)
set @colunas_pivot =
stuff((
select
distinct ‘,’ + quotename(RIGHT(CONVERT(varchar(10),C.dt_vencto,103),7))
from cta_pag C Join pag_lanc P
On C.seq_pag = P.seq_pag
for xml path(”)
), 1, 1, ”)
print @colunas_pivot
set @comando_sql = ‘
Select * From (
Select RIGHT(CONVERT(varchar(10),C.dt_vencto,103),7) As Mes_Ano,
O.descricao As Conta,
SUM(P.valor) As Valor
From cta_pag C Join pag_lanc P
On C.seq_pag = P.seq_pag
Join conta O
On O.cd_conta = P.cd_conta
Join empresa E
On E.cd_emp = C.cd_emp
Join fornec F
On F.cd_forn = C.cd_forn
Where C.dt_vencto >=’2023-01-01’
AND C.dt_vencto <='2023-03-31'
AND E.nome_fant = 'KAR TRANSPORTES'
Group By E.nome_fant,
RIGHT(CONVERT(varchar(10),C.dt_vencto,103),7),
O.descricao
) em_linhas
pivot (sum(valor) for Mes_Ano in (' + @colunas_pivot + ') em_colunas '
print @comando_sql
execute(@comando_sql)
Fala ai Isaias, tudo joia?
Posta no fórum fechado de alunos que eu respondo lá.
Abraço,
Josué
Olá Josué,
Espero que você esteja bem, agradeço por sempre ter um conteúdo de excelente qualidade.
Como mostrou para gerar uma PIVOT com colunas dinâmicas, é possível dar nomes para essas colunas?
Exemplo:
Anos em colunas dinâmicas
2022 | 2023
Resultado esperado
Ano de: 2022 | Ano de: 2023
Colaboradores em colunas dinâmicas
Abismail do Rosário | Chaves Rosembaum
Resultado esperado
Vendedor: Abismail do Rosário | Vendedor: Chaves Rosembaum
Fala ai Igor, boa tarde!
Obrigado meu amigo! Bem, deve haver inúmeras formas de fazer, a primeira que me ocorreu foi criar uma tabela temporária ou CTE com a sumarização dos múltiplos anos e/ou vendedores que você deseja, exemplo:
– Criar uma tb temp ou CTE, incluindo nela a sumarização das vendas de 2022 e 2023, tipo assim:
Anos | Valor da soma
2020 até 2021 | R$5000
2022 até 2023 | R$9000
…
– Com essa tabela em mãos, você usa o pivot de forma semelhante a que fizemos no vídeo para apresentar o resultado, tipo assim:
Colaborador | 2020 até 2021 | 2022 até 2023
João da Silva | R$ 1000 | R$ 2000
Maria Chiquinha | R$ 1500 | R$ 3000
…
O mesmo poderia ser feito para sumarizar colaboradores.
Essa é uma alternativa, não avaliei se é a melhor alternativa.
Abs
Josué
Boa tarde!
Josue,
Tentei aqui mas sem sucesso, eu estou precisando trazer o resultado de um banco de dados, onde ele tem varias linhas e algumas destas precisam ser colunas de acordo com o codigo unico.
Cada ID traz 5 linhas e preciso destas linhas Trazer para colunas para o mesmo ID..
Teria alguma sugestão?
Olá, boa tarde! O vídeo pivot com multiplas colunas (https://dba-pro.com/pivot-com-2-colunas-ou-mais/) atende a esse caso. abs Josué
Excelente artigo !!! Acrescentou bastante ao meu dia-a-dia
Alguém poderia talvez me dar uma luz ?
Tenho uma base assim
Codfuncionario | cod_centro_custo | perc_rateio
1 | 1 | 50%
1 | 2 | 50%
2 | 1 | 100%
E preciso transformá-la na seguinte forma dinamicamente:
codFuncionario | cod_centro_custo_1 | perc_valor1 | cod_centro_custo2 | perc_valor2 ..
1 | 1 | 50% | 2 | 50%
2 | 1 | 100% | NULL | NULL
Opa, boa tarde!
Valeu, seja bem-vindo ao blog! Em seu caso, talvez seja mais fácil realizar a tarefa em 2 etapas. Na primeira organiza centro de custo, na segunda adiciona ao resultset os nomes de colaboradores de forma dinâmica…
Abs
Josué
Muito bom mano… Você é brabo! kkkk
Fala ai Guilherme, valeu! Espero que ser brabo seja uma coisa boa! 🙂
Muiiitttttttttttooooooooooooo bom cara! Parabéns Josué! Salvou a pátria rsrs
Valeu Fabiano! 🙂