Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como converter valores de linha em colunas com contagem de colunas dinâmicas?


Minha sugestão sempre que você estiver trabalhando com PIVOT é sempre escrever a consulta primeiro com os valores codificados, então você pode facilmente converter a consulta em uma solução dinâmica.

Como você terá vários valores de columnC que será convertido em colunas, então você precisa olhar usando o row_number() função de janela para gerar uma sequência única para cada columnc com base nos valores de columnA e columnB .

O ponto de partida para sua consulta será:
select [ColumnA],
  [ColumnB],
  [ColumnC],
  'SampleTitle'+
  cast(row_number() over(partition by columna, columnb
                          order by columnc) as varchar(10)) seq
from DataSource;

Veja Demonstração. Esta consulta irá gerar a lista de novos nomes de colunas SampleTitle1 , etc:
| COLUMNA | COLUMNB | COLUMNC |          SEQ |
|---------|---------|---------|--------------|
|    5060 |    1006 |  100118 | SampleTitle1 |
|    5060 |    1006 |  100119 | SampleTitle2 |
|    5060 |    1006 |  100120 | SampleTitle3 |

Você pode então aplicar o pivô em columnC com os novos nomes de coluna listados em seq :
select columnA, columnB, 
  SampleTitle1, SampleTitle2, SampleTitle3
from
(
   select [ColumnA],
    [ColumnB],
    [ColumnC],
    'SampleTitle'+
      cast(row_number() over(partition by columna, columnb
                              order by columnc) as varchar(10)) seq
   from DataSource
) d
pivot
(
  max(columnc)
  for seq in (SampleTitle1, SampleTitle2, SampleTitle3)
) piv;

Consulte SQL Fiddle com demonstração.

Depois de ter a lógica correta, você pode converter os dados em SQL dinâmico. A chave aqui é gerar a lista de novos nomes de coluna. Eu normalmente uso FOR XML PATH para isso semelhante a:
select STUFF((SELECT distinct ',' + QUOTENAME(seq) 
                from
                (
                  select 'SampleTitle'+
                    cast(row_number() over(partition by columna, columnb
                                            order by columnc) as varchar(10)) seq
                  from DataSource
                ) d
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')

Veja Demonstração. Depois de ter a lista de nomes de colunas, você gerará sua string sql para executar, o código completo será:
DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(seq) 
                    from
                    (
                      select 'SampleTitle'+
                        cast(row_number() over(partition by columna, columnb
                                                order by columnc) as varchar(10)) seq
                      from DataSource
                    ) d
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT columnA, ColumnB,' + @cols + ' 
             from 
             (
               select [ColumnA],
                [ColumnB],
                [ColumnC],
                ''SampleTitle''+
                  cast(row_number() over(partition by columna, columnb
                                          order by columnc) as varchar(10)) seq
               from DataSource
            ) x
            pivot 
            (
                max(columnc)
                for seq in (' + @cols + ')
            ) p '

execute sp_executesql @query;

Consulte SQL Fiddle com demonstração. Estes dão um resultado:
| COLUMNA | COLUMNB | SAMPLETITLE1 | SAMPLETITLE2 | SAMPLETITLE3 |
|---------|---------|--------------|--------------|--------------|
|    5060 |    1006 |       100118 |       100119 |       100120 |
|    5060 |    1007 |       100121 |       100122 |       (null) |
|    5060 |    1012 |       100123 |       (null) |       (null) |