简体   繁体   English

动态pivot和static pivot在Z9778840A0100CB30C982Z876741B0B5A2服务器组合

[英]Combination of dynamic pivot and static pivot in SQL Server

Dynamic pivot combined combined with static aggregates动态 pivot 结合 static 聚合

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:我基本上需要:

  • Group by a number of fields (Place, State, Category in the example)按多个字段分组(例如,地点、State、类别)
  • Count per such group每个这样的组计数
  • Sum MCount, Cost (and others, not in example) per group, these columns are static每组总和 MCount、成本(和其他,不在示例中),这些列是 static
  • Pivot over Category and sum CategCount for each such grouped category (here Old, Young). Pivot 超过 Category 并为每个此类分组类别(此处为 Old,Young)求和 CategCount。 This is the dynamic part这是动态部分

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 关于这一切都错了?

What I've got so far:到目前为止我得到了什么:

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:以下为我提供了OldYoung的正确动态 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:返回:

在此处输入图像描述

But it should look something like this:但它应该看起来像这样:

在此处输入图像描述

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 state Category类别 SumMCount总和计数 Old老的 Young年轻的 SumCost总成本 SumBuys SumBuys
2 2 London伦敦 UK英国 Old老的 5 5 9 9 0 0 26 26 25 25
1 1 Brussels布鲁塞尔 BE Young年轻的 0 0 0 0 2 2 3 3 4 4
2 2 Brussels布鲁塞尔 BE null null 7 7 0 0 0 0 2 2 13 13

db<>fiddle here db<> 在这里摆弄

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM