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