【问题标题】:TSQL Pivot - Collapsing Columns to RowsTSQL Pivot - 将列折叠为行
【发布时间】:2016-02-04 12:23:55
【问题描述】:

使用 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

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

【问题讨论】:

    标签: sql sql-server tsql pivot unpivot


    【解决方案1】:

    一种可能的解决方案,没有枢轴/取消枢轴:

    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
    

    【讨论】:

      【解决方案2】:

      简单的方法就是合并你原来的:

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

      【讨论】:

      • 正在研究一些完全动态的东西,因为商店可能会随时发生变化。感谢您的建议!
      【解决方案3】:

      您也可以用很少的代码动态构建一个 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)
      

      【讨论】:

        猜你喜欢
        • 2022-01-09
        • 1970-01-01
        • 2023-04-07
        • 2013-11-04
        • 2019-08-07
        • 2012-06-20
        • 2018-11-08
        • 1970-01-01
        • 2013-01-20
        相关资源
        最近更新 更多