我有一张要重塑的桌子,目前看起来像这样:
ID Year Channel Payments
1 2012 HV 100
1 2014 HV 56
2 2012 NL 17000
2 2012 HV 495
3 2013 HV 565
等...有很多行。
我需要调整数据的形状,以使每个ID一行一行,并在多列中分别显示各年和每个频道的付款。例如,上表将如下所示:
ID HV2012 HV2013 HV2014 NL2012
1 100 NULL 56 NULL
2 495 NULL NULL 17000
3 NULL 565 NULL NULL
过去我可以在R中使用dplyr来轻松实现此目的,但现在需要使用SQL Server。我无法找到一种无需指定每个新列名称的方法-由于我的数据涵盖了许多渠道和年份,因此这实际上是不可行的。我了解它可能需要动态SQL,但是我对此没有经验。
谢谢
答案 0 :(得分:3)
您可以使用动态数据透视查询来实现。
-- data
create table testTable
(
Id int,
Year int,
Channel varchar(10),
Payments int
)
insert into testTable values (1,2012,'HV',100)
insert into testTable values (1,2014,'HV',56)
insert into testTable values (2,2012,'NL',17000)
insert into testTable values (2,2012,'HV',495)
insert into testTable values (3,2013,'HV',565)
-- query
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(CONCAT(c.Channel,c.Year))
FROM testTable c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT Id, ' + @cols + ' from
(
select Id
, CONCAT(Channel,Year ) YC
, Payments
from testTable
) x
pivot
(
max(Payments)
for YC in (' + @cols + ')
) p '
execute(@query)
答案 1 :(得分:1)
您可以找到类似的查询,该查询也将在较低版本的SQL Server中运行。
-- query
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(Channel + Convert(Varchar(4) ,Year))
FROM testTable c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT Id, ' + @cols + ' from
(
select Id, Payments,
Channel + Convert(Varchar(4) ,Year) NewCol
from testTable
) x
pivot
(
max(Payments)
for NewCol in (' + @cols + ')
) p '
execute(@query)
您可以找到实时演示here。
编辑
要将数据保存在临时表中,您可以尝试以下查询。
create table MyTable
(
Id int,
Year int,
Channel varchar(10),
Payments int
)
insert into MyTable values
(1,2012,'HV',100),
(1,2014,'HV',56),
(2,2012,'NL',17000),
(2,2012,'HV',495),
(3,2013,'HV',565)
Declare @SQL varchar(max) = '
if object_id(''##TestTable'') is not null
begin
drop table ##TestTable
end
create table ##TestTable([Id] int null, ' +
Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year)) + ' Varchar(20) null'
From [dbo].MyTable
Order By 1
For XML Path('')),1,1,'')+ ')
INSERT INTO ##TestTable
Select *
From (
Select A.ID, A.Payments
,B.*
From [dbo].MyTable a
Cross Apply ( values ( Channel + CONVERT(Varchar(4), Year)
)) B ([Value])
) S
Pivot (sum([Payments]) For [Value] in
(' + Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year))
From myTable
Order By 1
For XML Path('')),1,1,'') + ') ) p'
--SELECT @SQL
Exec(@SQL)
SELECT * FROM ##TestTable
您可以找到演示here。