TSQL Pivot - 将列折叠成行

TSQL Pivot - Collapsing Columns to Rows

使用 PIVOT/UNPIVOT 我可以从这里...

Period       Store1         Store2
--------------------------------------
Jan15        123            456
Feb15        789            101
Mar15        112            131
Apr15        415            161

...到这里,动态地(无论有多少存储我当前的脚本成功地 PIVOT 到下面的集合...

Store        Jan15          Feb15          Mar15          Apr15
---------------------------------------------------------------
Store1       123            789            112            415
Store2       456            101            131            161

使用这个脚本:

DECLARE @colsUnpivot AS NVARCHAR(MAX), 
         @colsPivot as  NVARCHAR(MAX), @query  AS NVARCHAR(MAX)        

/* @colsUnpivot gets list of Stores */
select @colsUnpivot = COALESCE(@colsUnpivot +', ', '') + QUOTENAME(A.name)
from (select name 
        from sys.columns 
       where object_id = object_id('mytable') and name <> 'Period') A

/* @colsPivot gets list of Periods */
select @colsPivot = COALESCE(@colsPivot +', ', '') + QUOTENAME(B.Period)
  from (select distinct period 
          from StoreMetrics) B

set @query 
  = 'select store, '+@colsPivot+'
      from
      (
        select period, store, value
        from mytable
        unpivot
        (
          value for store in ('+@colsUnpivot+')
        ) unpiv
      ) src
      pivot
      (
        max(value)
        for period in ('+@colsPivot+')
      ) piv'

exec(@query)

...然而,这是实际预期的结果集:

Store        Period         Value
--------------------------------------
Store1       Jan15          123            
Store1       Feb15          789
Store1       Mar15          112
Store1       Apr15          415
Store2       Jan15          456
Store2       Feb15          101
Store2       Mar15          131
Store2       Apr15          161

无论是从原始数据集还是我的第一个数据透视结果,对于 element/period 的每个组合,我如何动态地将所有列折叠(必须是动态的,因为周期条目会不断变化)到行条目?

简单的方法就是合并您的原始文件:

    DECLARE @t AS TABLE(period VARCHAR(15), store1 INT, store2 INT)

    INSERT INTO @t
            ( [period], [store1], [store2] )
    VALUES  
    ('Jan15',123,456), 
    ('Feb15',789,101),
    ('Mar15',112,131)

    SELECT 
    T1.[period],
    'Store1' AS Store,
    [T1].[store1] AS Value
    FROM @t AS T1

    UNION 

    SELECT 
    T1.[period],
    'Store2',
    [T1].[store2]
    FROM @t AS T1
   ORDER BY Store

给出:

period  Store   Value
Feb15   Store1  789
Jan15   Store1  123
Mar15   Store1  112
Feb15   Store2  101
Jan15   Store2  456
Mar15   Store2  131

然后这只是对结果进行排序的问题,您可以通过添加一个基于 Period 的整数排序键来进行排序。

一个可能的解决方案,没有pivot/unpivot:

create table #tab(
    Store  nvarchar(50),
    period nvarchar(50),
    value int
)

declare @ColumnName table(columnName nvarchar(50))

insert into @ColumnName (columnName)
select  A.name
from    (
            select  name
            from    sys.columns
            where   object_id = object_id('mytable')
                    and name <> 'Period'
        ) A

declare @Column nvarchar(50),
        @sql    nvarchar(4000)

while (select  count(*) from    @ColumnName) > 0
begin
    set @Column = (select  top 1 columnName from @ColumnName);
    set @sql = '
           insert into #tab 
           select ''' + @Column + ''',Period , sum(' + @Column + ')
           from mytable
           group by ' + @Column + ',Period'


    exec(@sql);

    delete from @ColumnName
    where   columnName = @Column
end

select  *
from    #tab

drop table #tab

您也可以只用很少的代码动态构建 UNION ALL 查询。

DECLARE @SQL NVARCHAR(MAX),
        @Select NVARCHAR(MAX) = 'SELECT ''<<storename>>'' AS Store, Period, <<storename>> AS Value FROM MyTable'

SELECT  @SQL = COALESCE(@SQL + ' UNION ALL ','') + REPLACE(@Select,'<<storename>>',name)
FROM    sys.columns
WHERE   object_id = OBJECT_ID('mytable')
        AND name <> 'Period'

EXEC(@SQL)