TSQL Pivot - 将列折叠到行

时间:2016-02-04 12:23:55

标签: sql sql-server tsql pivot unpivot

使用PIVOT / UNPIVOT我能从这里得到......

""

...动态到这里(无论我当前脚本有多少存储成功PIVOT到以下设置......

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

使用此脚本:

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)

从原始数据集或我的第一个数据透视结果中,如何动态折叠(必须是动态的,因为句点条目将不断变化)所有列都是每个元素/句点组合的行条目?

3 个答案:

答案 0 :(得分:1)

一种可能的解决方案,没有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

答案 1 :(得分:0)

简单的方法就是结合原作:

    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的整数排序键来排序。

答案 2 :(得分:0)

您也可以使用非常少的代码动态构建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)