sql 服务器 - 使用动态枢轴转换数据
sql server - transforming data with dynamic pivot
我需要动态转换 table #table 格式的数据:
spot_id name pct
------- ---- ---
1 A 2
1 B 8
1 C 6
2 A 4
2 B 5
3 A 5
3 D 1
3 E 4
至:
spot_id A B C D E
------- --- --- --- --- ---
1 2 5 6 0 0
2 4 5 0 0 0
3 5 0 0 1 4
问题是我事先不知道列 "name" 的值是什么或者它们有多少,所以我认为我必须使用某种动态 SQL旋转
刚想出解决问题的方法:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(name)
from (SELECT DISTINCT name FROM #table) T
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = N'SELECT spot_id,' + @cols + N' from
(
select spot_id, name, pct
from #table
) as x
pivot
(
max(pct)
for name in (' + @cols + N')
) as p '
exec sp_executesql @query;
是否有更优雅的方法来做同样的事情?
declare @t table (Spot int,name varchar(1),pct int)
insert into @t(Spot,name,pct)values(1,'A',2),(1,'B',8),(1,'C',6),(2,'A',4),(2,'B',5),(3,'A',5),(3,'D',1),(3,'E',4)
select Spot,ISNULL([A],0)[A],ISNULL([B],0)[B],ISNULL([C],0)[C],ISNULL([D],0)[D],ISNULL([E],0)[E] from (Select Spot,PCT,Name from @t)T
PIVOT(MAX(PCT) FOR Name IN ([A],[B],[C],[D],[E]))P
select Spot,ISNULL(MAX(CASE WHEN name = 'A' THEN pct END),0)A,ISNULL(MAX(CASE WHEN name = 'B' THEN pct END),0)B ,
ISNULL(MAX(CASE WHEN name = 'C' THEN pct END),0)C ,
ISNULL(MAX(CASE WHEN name = 'D' THEN pct END),0)D ,ISNULL(MAX(CASE WHEN name = 'E' THEN pct END),0)E from @t
GROUP BY Spot
使用动态查询:
if object_id('tempdb..#t') is not null
drop table #t
CREATE table #t(Spot int,name varchar(1),pct int)
insert into #t(Spot,name,pct)values(1,'A',2),(1,'B',8),(1,'C',6),(2,'A',4),(2,'B',5),(3,'A',5),(3,'D',1),(3,'E',4)
DECLARE @statement NVARCHAR(max)
,@columns NVARCHAR(max)
SELECT @columns = ISNULL(@columns + ', ', '') + N'[' + tbl.name + ']'
FROM (
SELECT DISTINCT name
FROM #t
) AS tbl
SELECT @statement = ' select Spot,ISNULL([A],0)[A],ISNULL([B],0)[B],ISNULL([C],0)[C],ISNULL([D],0)[D],ISNULL([E],0)[E] from (Select Spot,PCT,Name from #t)T
PIVOT(MAX(PCT) FOR Name IN (' + @columns + ')) as pvt'
EXEC sp_executesql @statement = @statement
我需要动态转换 table #table 格式的数据:
spot_id name pct ------- ---- --- 1 A 2 1 B 8 1 C 6 2 A 4 2 B 5 3 A 5 3 D 1 3 E 4
至:
spot_id A B C D E ------- --- --- --- --- --- 1 2 5 6 0 0 2 4 5 0 0 0 3 5 0 0 1 4
问题是我事先不知道列 "name" 的值是什么或者它们有多少,所以我认为我必须使用某种动态 SQL旋转
刚想出解决问题的方法:
DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX) select @cols = STUFF((SELECT ',' + QUOTENAME(name) from (SELECT DISTINCT name FROM #table) T FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'') set @query = N'SELECT spot_id,' + @cols + N' from ( select spot_id, name, pct from #table ) as x pivot ( max(pct) for name in (' + @cols + N') ) as p ' exec sp_executesql @query;
是否有更优雅的方法来做同样的事情?
declare @t table (Spot int,name varchar(1),pct int)
insert into @t(Spot,name,pct)values(1,'A',2),(1,'B',8),(1,'C',6),(2,'A',4),(2,'B',5),(3,'A',5),(3,'D',1),(3,'E',4)
select Spot,ISNULL([A],0)[A],ISNULL([B],0)[B],ISNULL([C],0)[C],ISNULL([D],0)[D],ISNULL([E],0)[E] from (Select Spot,PCT,Name from @t)T
PIVOT(MAX(PCT) FOR Name IN ([A],[B],[C],[D],[E]))P
select Spot,ISNULL(MAX(CASE WHEN name = 'A' THEN pct END),0)A,ISNULL(MAX(CASE WHEN name = 'B' THEN pct END),0)B ,
ISNULL(MAX(CASE WHEN name = 'C' THEN pct END),0)C ,
ISNULL(MAX(CASE WHEN name = 'D' THEN pct END),0)D ,ISNULL(MAX(CASE WHEN name = 'E' THEN pct END),0)E from @t
GROUP BY Spot
使用动态查询:
if object_id('tempdb..#t') is not null
drop table #t
CREATE table #t(Spot int,name varchar(1),pct int)
insert into #t(Spot,name,pct)values(1,'A',2),(1,'B',8),(1,'C',6),(2,'A',4),(2,'B',5),(3,'A',5),(3,'D',1),(3,'E',4)
DECLARE @statement NVARCHAR(max)
,@columns NVARCHAR(max)
SELECT @columns = ISNULL(@columns + ', ', '') + N'[' + tbl.name + ']'
FROM (
SELECT DISTINCT name
FROM #t
) AS tbl
SELECT @statement = ' select Spot,ISNULL([A],0)[A],ISNULL([B],0)[B],ISNULL([C],0)[C],ISNULL([D],0)[D],ISNULL([E],0)[E] from (Select Spot,PCT,Name from #t)T
PIVOT(MAX(PCT) FOR Name IN (' + @columns + ')) as pvt'
EXEC sp_executesql @statement = @statement