基于两列传播数据 table,SQL 服务器
Spread data table based on two columns, SQL server
我有一个 table 我想重新整形,目前看起来像这样:
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 一行,多列显示每年和每个渠道的付款。例如,上面的 table 看起来像这样:
ID HV2012 HV2013 HV2014 NL2012
1 100 NULL 56 NULL
2 495 NULL NULL 17000
3 NULL 565 NULL NULL
过去我在 R 中使用 dplyr 可以很容易地做到这一点,但现在需要使用 SQL 服务器。我一直无法找到无需指定每个新列的名称即可执行此操作的方法 - 因为我的数据涵盖许多频道和年份,这实际上并不可行。我知道它可能需要动态 SQL,但我没有使用它的经验。
谢谢
您可以使用动态数据透视查询来实现这一点。
-- 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)
您也可以在较低版本的 SQL 服务器中找到 运行 的类似查询。
-- 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。
编辑
要在临时文件中保存数据 table 您可以尝试以下查询。
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。
我有一个 table 我想重新整形,目前看起来像这样:
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 一行,多列显示每年和每个渠道的付款。例如,上面的 table 看起来像这样:
ID HV2012 HV2013 HV2014 NL2012
1 100 NULL 56 NULL
2 495 NULL NULL 17000
3 NULL 565 NULL NULL
过去我在 R 中使用 dplyr 可以很容易地做到这一点,但现在需要使用 SQL 服务器。我一直无法找到无需指定每个新列的名称即可执行此操作的方法 - 因为我的数据涵盖许多频道和年份,这实际上并不可行。我知道它可能需要动态 SQL,但我没有使用它的经验。
谢谢
您可以使用动态数据透视查询来实现这一点。
-- 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)
您也可以在较低版本的 SQL 服务器中找到 运行 的类似查询。
-- 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。
编辑
要在临时文件中保存数据 table 您可以尝试以下查询。
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。