T-SQL分组总和,基于帮助表

时间:2017-07-03 13:52:51

标签: sql-server tsql sum case

我有一个包含分组列和数字列的表,我想总结一下。我的表看起来像这样:

  Person   Object    Count  
 -------- --------- ------- 
  John     apples        1  
  John     pears         6  
  John     ferrari      10  
  Mike     porsche       3  
  Mike     ferrari       1  

我想创建一个每人返回一行的表,并返回包含一组对象的多个列。在这个例子中,苹果和梨都是水果和法拉利,而保时捷都是汽车。我的结果表看起来像这样:

  Person   Fruits   Cars  
 -------- -------- ------ 
  John          7     10  
  Mike          0      4  

我有一个帮助表,可以将每个对象分配给一个组。组的数量是一成不变的,但我可能会在每组中添加更多对象。这就是我创建这个帮助表的原因,这样当我的数据中有新对象时,我可以简单地添加一行。例如,我可能稍后添加李子(也是水果)或丰田(也是汽车),但我绝不会添加任何不是汽车或水果的东西。

  Object    Group   
 --------- -------- 
  apples    fruits  
  pears     fruits  
  ferrari   cars    
  porsche   cars    

我的解决方案是以下查询:

SELECT
  Person,
  SUM(CASE WHEN Object IN (SELECT Object FROM help_table WHERE Group = 'fruits') THEN Count END) AS Fruits,
  SUM(CASE WHEN Object IN (SELECT Object FROM help_table WHERE Group = 'cars') THEN Count END) AS Cars
FROM start_table
GROUP BY Person

它返回以下错误:

Cannot perform an aggregate function on an expression containing an aggregate or a subquery.

我正在寻找其他解决方案以达到预期效果。在查询中可以很容易地指定哪些对象属于每个组,但我真的更喜欢将新对象添加到表中,而不必对其进行硬编码。

4 个答案:

答案 0 :(得分:1)

这适用于一组有限的小组

SELECT
  Person,
  COUNT(hf.Object),
  COUNT(hc.Object)
FROM 
  start_table s
  LEFT join
  help_table hf ON s.Object = hf.Object AND hf.Group = 'fruits'
  LEFT join
  help_table hc ON s.Object = hc.Object AND hc.Group = 'cars'
GROUP BY Person

每组添加一个新列会变得更加棘手,因为SQL并不真正支持任意列输出

答案 1 :(得分:1)

创建两个表,水果和汽车:

SELECT
  s.Person,
  sum(fruits.count) as Fruits,
  sum(cars.count) AS Cars
FROM start_table s
    left join help_table fruits on s.[Object] = fruits.[Object] and fruits.[Group] = 'fruits'
    left join help_table cars on s.Object = cars.Object and cars.[Group] = 'cars'
GROUP BY s.Person

答案 2 :(得分:1)

您可以使用sum和pivot如下:

 Select * from (
     Select [Person], [Group], sum([Count]) as sm from start_table s
        left join help_table h
        on s.[Object] = h.[Object]
        group by [Person], [Group]
    ) a
    pivot (sum(sm) for [Group] in ([fruits],[cars])) p

对于[Group]的动态列表,您可以查询如下

Declare @cols1 varchar(max)
Declare @query nvarchar(max)

Select @cols1 = stuff((select distinct ','+QuoteName([Group]) from help_table  for xml path('')),1,1,'')

Set @query = '   Select * from (
         Select [Person], [Group], [Count] from start_table s
            left join help_table h
            on s.[Object] = h.[Object]
        ) a
        pivot (sum([Count]) for [Group] in (' + @cols1 + ')) p '

Exec sp_executesql @query

答案 3 :(得分:0)

您可以使用公用表表达式轻松获得此功能。下面的查询将给出所需格式的结果。我还在here创建了一个sqlfiddle。有时SqlFiddle无法正确加载,请在链接上重试。请随便看看。

SELECT
  Person,
  ISNULL(Cars, 0) Cars,
  ISNULL(Fruits, 0) Fruits
FROM (SELECT
  Person,
  [Group],
  SUM([Count]) AS TotalCount
FROM Userdata
JOIN ItemGroup
  ON ItemGroup.Item = Userdata.Item
GROUP BY Person,
         [Group]) x
PIVOT
(
SUM(TotalCount)
FOR [Group] IN ([fruits], [cars])
) pvt