[英]Combination of dynamic pivot and static pivot in SQL Server
I have a table that looks something like this:我有一个看起来像这样的表:
Place State Category CategCount MCount Buys Cost
London UK Old 3 NULL 22 4.50
London UK Old 6 5 3 22.00
Brussels BE Young 2 NULL 4 3.50
Brussels BE M NULL 5 12 1.20
Brussels BE M NULL 2 1 1.20
I basically need to:我基本上需要:
Result should look like:结果应如下所示:
Count Place State Category SumMCount SumOld SumYoung SumCost SumBuys
2 London UK Old 5 9 0 26.50 25
1 Brussels BE Young 0 0 2 3.50 4
2 Brussels BE NULL 7 0 0 2.40 13
I know how to get a dynamic pivot query (as per https://stackoverflow.com/a/38505375/111575 ) and I know how to do the static part.我知道如何获得动态 pivot 查询(根据https://stackoverflow.com/a/38505375/111575 )并且我知道如何执行 ZA81259CEF8E959C624ZDF1DDEDD452 部分。 But I don't know how to combine the two.
但我不知道如何将两者结合起来。 Anybody any ideas?
有人有什么想法吗? Maybe I go about it all wrong?
也许我 go 关于这一切都错了?
The following gives me the proper dynamic pivot results for Old
and Young
, but not sure how to add the count and the the 'regular' sums/aggregates to it:以下为我提供了
Old
和Young
的正确动态 pivot 结果,但不确定如何将计数和“常规”总和/聚合添加到其中:
create table #temp
(
Place nvarchar(20),
State nvarchar(20),
Category nvarchar(20) null,
CategCount int null,
MCount int null,
Buys int,
Cost int
)
insert into #temp values ('London', 'UK', 'Old', 3, NULL, 22, 4.50)
insert into #temp values ('London', 'UK', 'Old', 6, 5, 3, 22.00)
insert into #temp values ('Brussels', 'BE', 'Young', 2, NULL, 4, 3.50)
insert into #temp values ('Brussels', 'BE', 'M', NULL, 5, 12, 1.20)
insert into #temp values ('Brussels', 'BE', 'M', NULL, 2, 1, 1.20)
DECLARE @cols AS NVARCHAR(MAX)='';
DECLARE @query AS NVARCHAR(MAX)='';
SELECT @cols = @cols + QUOTENAME(Category) + ',' FROM (select distinct Category from #temp where CategCount IS NOT NULL) as tmp
select @cols = substring(@cols, 0, len(@cols)) --trim "," at end
--select (@cols) as bm
set @query =
'SELECT * from
(
select
sum(CategCount) as totalCatCount,
Category
from #temp
group by Category
) src
pivot
(
max(totalCatCount) for Category in (' + @cols + ')
) piv'
execute(@query)
drop table #temp
Returning:返回:
And the following is the 'regular' query without the pivoting:以下是没有旋转的“常规”查询:
select count(*) as count, place, state, category,
sum(ISNULL(CategCount, 0)) as SumCatCount,
sum(ISNULL(MCount, 0)) as SumMCount,
sum(ISNULL(buys, 0)) as SumBuys,
sum(Cost) as SumCost
from #temp
group by place, state, category
Returning:返回:
I have used your static pivot part of the query as the source of dynamic pivot.我已使用您的 static pivot 部分查询作为动态 pivot 的来源。 Create two sets of dynamic pivot column list.
创建两组动态 pivot 列列表。 One for pivoting and the another with Coalesce() to select pivoted columns (to convert null into 0).
一个用于旋转,另一个使用 Coalesce() 到 select 旋转列(将 null 转换为 0)。 If there is no categcount for any category then that category has been replaced with null (case when).
如果没有任何类别的类别计数,则该类别已替换为 null(情况何时)。 Two more aliases for Category and SumCatCount have been created since those were used in pivot condition.
自从在 pivot 条件下使用之后,已经创建了另外两个 Category 和 SumCatCount 别名。
Here goes your answer:这是你的答案:
create table #temp
(
Place nvarchar(20),
State nvarchar(20),
Category nvarchar(20) null,
CategCount int null,
MCount int null,
Buys int,
Cost int
)
insert into #temp values ('London', 'UK', 'Old', 3, NULL, 22, 4.50)
insert into #temp values ('London', 'UK', 'Old', 6, 5, 3, 22.00)
insert into #temp values ('Brussels', 'BE', 'Young', 2, NULL, 4, 3.50)
insert into #temp values ('Brussels', 'BE', 'M', NULL, 5, 12, 1.20)
insert into #temp values ('Brussels', 'BE', 'M', NULL, 2, 1, 1.20)
DECLARE @cols AS NVARCHAR(MAX)='';
DECLARE @query AS NVARCHAR(MAX)='';
DECLARE @colsForSelect AS NVARCHAR(MAX)='';
SET @cols = STUFF((SELECT distinct ',' + quotename(category)
FROM #temp where CategCount is not null
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET @colsForSelect = STUFF((SELECT distinct ',' + ' Coalesce('+quotename(category)+',0) '+ quotename(category)
FROM #temp where CategCount is not null
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
--select (@cols) as bm
set @query =
'SELECT count,place,state,(case when OldSumCatCount >0 then OldCategory else null end)Category,SumMCount, ' + @colsForSelect + ',SumCost,SumBuys from
(
select count(*) as count, place, state,category OldCategory, category,
sum(ISNULL(MCount, 0)) as SumMCount,
sum(ISNULL(CategCount, 0)) as OldSumCatCount,
sum(ISNULL(CategCount, 0)) as SumCatCount,
sum(Cost) as SumCost,
sum(ISNULL(buys, 0)) as SumBuys
from #temp
group by place , state, category
) src
pivot
(
max(SumCatCount) for Category in (' + @cols + ')
) piv
order by place desc,count'
execute(@query)
GO
count![]() |
place![]() |
state ![]() |
Category![]() |
SumMCount![]() |
Old![]() |
Young![]() |
SumCost![]() |
SumBuys ![]() |
---|---|---|---|---|---|---|---|---|
2 ![]() |
London![]() |
UK![]() |
Old![]() |
5 ![]() |
9 ![]() |
0 ![]() |
26 ![]() |
25 ![]() |
1 ![]() |
Brussels![]() |
BE![]() |
Young![]() |
0 ![]() |
0 ![]() |
2 ![]() |
3 ![]() |
4 ![]() |
2 ![]() |
Brussels![]() |
BE![]() |
null ![]() |
7 ![]() |
0 ![]() |
0 ![]() |
2 ![]() |
13 ![]() |
Thanks to @Larnu in the comments for pointing me in the right direction.感谢评论中的@Larnu 为我指明了正确的方向。 His/her statement on "you cannot JOIN a static to a dynamic query" and that either all or nothing has to be dynamic, prompted me to build onto the dynamic part and simply extend it.
他/她关于“您不能将 static 加入动态查询”的声明,并且要么全部要么全部都必须是动态的,这促使我构建动态部分并简单地扩展它。
I thought I needed to repeat the columns somehow in the PIVOT
section, but that appears to not be the case.我以为我需要在
PIVOT
部分以某种方式重复这些列,但情况似乎并非如此。 Only the column you want to pivot, apparently (logically so, once you think about it).显然,只有您想要 pivot 的列(逻辑上如此,一旦您考虑一下)。
The only part I haven't figured out yet is how to get rid of NULL
in the resulting set, hopefully someone answers with that in mind;).我还没有弄清楚的唯一部分是如何在结果集中摆脱
NULL
,希望有人能想到这一点;)。
DECLARE @cols AS NVARCHAR(MAX)='';
DECLARE @query AS NVARCHAR(MAX)='';
SELECT @cols = @cols + QUOTENAME(Category) + ',' FROM (select distinct Category from #temp where CategCount IS NOT NULL) as tmp
select @cols = substring(@cols, 0, len(@cols)) --trim "," at end
--select (@cols) as bm
set @query =
'SELECT * from
(
select
count(*) as count,
Place,
State,
Category,
Category as CatPivot,
sum(ISNULL(CategCount, 0)) as TotalCatCount,
sum(ISNULL(Buys, 0)) as SumBuys,
sum(ISNULL(Cost, 0)) as SumCost,
sum(ISNULL(MCount, 0)) as SumMCount
from #temp
group by Category, Place, State
) src
pivot
(
max(TotalCatCount) for CatPivot in (' + @cols + ')
) piv'
execute(@query)
Here I am sharing another answer which is same but as suggested by @Anthony Hancock dynamic column names for pivot have been created with string_agg() instead of stuff() and xml path for().在这里,我分享了另一个相同的答案,但正如@Anthony Hancock 建议的那样,pivot 的动态列名是用 string_agg() 而不是 stuff() 和 xml 路径 for() 创建的。 It's way too faster and more readable (for SQL Server 2017 and onward)
它的速度更快,可读性更强(对于 SQL Server 2017 及更高版本)
DECLARE @cols AS NVARCHAR(MAX)='';
DECLARE @query AS NVARCHAR(MAX)='';
DECLARE @colsForSelect AS NVARCHAR(MAX)='';
select @cols =string_agg(category,',') from (
select distinct category FROM #temp where CategCount is not null )t
select @colsForSelect= STRING_AGG(category,',') from
(select distinct 'coalesce('+category+',0) '+category category FROM #temp where CategCount is not null )t
set @query =
'SELECT count,place,state,(case when OldSumCatCount >0 then OldCategory else null end)Category,SumMCount, ' + @colsForSelect + ',SumCost,SumBuys from
(
select count(*) as count, place, state,category OldCategory, category,
sum(ISNULL(MCount, 0)) as SumMCount,
sum(ISNULL(CategCount, 0)) as OldSumCatCount,
sum(ISNULL(CategCount, 0)) as SumCatCount,
sum(Cost) as SumCost,
sum(ISNULL(buys, 0)) as SumBuys
from #temp
group by place , state, category
) src
pivot
(
max(SumCatCount) for Category in (' + @cols + ')
) piv
order by place desc,count'
execute(@query)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.