以两种不同的方式汇总数据

时间:2016-05-26 05:21:12

标签: sql sql-server tsql cube rollup

假设我有一个存储客户名称,设备号和一些标志的表。一些示例数据看起来像这样:

[CustomerName], [Device], [A], [B], [C]
'Customer A',   '1234',   1,   0,   0
'Customer A',   '1235',   1,   1,   1
'Customer A',   '1234',   1,   1,   1
'Customer B',   '1236',   1,   1,   0
'Customer B',   '1236',   1,   0,   0
'Customer C',   '1235',   1,   1,   1

我需要一份同时显示3种数据类型的报告:

  • 每个标志的总行数
  • 每个客户每个标记的行数
  • 每个标记显示在任何行中的唯一设备数

前两个项目使用ROLLUP相对容易创建,但最后一个项目比较棘手。我能弄清楚如何做到这一点的唯一方法是使用UNION

SELECT CASE WHEN (GROUPING([CustomerName]) = 1) THEN 'ALL CUSTOMERS' 
       ELSE [CustomerName] END [CustomerName], 
       COUNT(*) [Rows], 
       SUM(CAST([A] AS [int])) [A], 
       SUM(CAST([B] AS [int])) [B], 
       SUM(CAST([C] AS [int])) [C]
  FROM [MyTable]
 GROUP BY [CustomerName] WITH ROLLUP
 UNION
SELECT 'UNIQUE DEVICES', 
       COUNT(*),
       SUM(CASE WHEN [A] > 0 THEN 1 ELSE 0 END),
       SUM(CASE WHEN [B] > 0 THEN 1 ELSE 0 END),
       SUM(CASE WHEN [C] > 0 THEN 1 ELSE 0 END)
  FROM (
    SELECT [Device],
           COUNT(*) [Rows], 
           SUM(CAST([A] AS [int])) [A], 
           SUM(CAST([B] AS [int])) [B], 
           SUM(CAST([C] AS [int])) [C]
      FROM [MyTable]
     GROUP BY [Device] ) q

结果:

[CustomerName],   [Rows], [A], [B], [C]
'ALL CUSTOMERS',  6,      6,   4,   3
'Customer A',     3,      3,   2,   2
'Customer B',     2,      2,   1,   0
'Customer C',     1,      1,   1,   1
'UNIQUE DEVICES', 3,      3,   3,   2

这对我现在的目的来说已经足够好了,但之前没有多少使用ROLLUPCUBE的经验,我想我会试着看看我是否可以摆脱它UNION并且只有一个SELECT。从examples on MSDN开始,ROLLUP支持多个分组,但我无法弄清楚如何让它产生我想要的结果。任何人都可以演示如何使用单个SELECT来获得这些结果吗?

1 个答案:

答案 0 :(得分:0)

  

我需要一份同时显示3种数据类型的报告:

这并不一定意味着您需要一个查询。您想要的结果在逻辑上是不同的。还有其他方法可以将它们组合在一起,但最简单的查询是三者的结合:

select   CustomerName
       , count(*) as Rows
       , sum(cast(A as int)) as A
       , sum(cast(B as int)) as B
       , sum(cast(C as int)) as C
from T
group by CustomerName
UNION
select   'ALL CUSTOMERS'
       , count(*) as Rows
       , sum(cast(A as int)) as A
       , sum(cast(B as int)) as B
       , sum(cast(C as int)) as C
from T
UNION
select   'UNIQUE DEVICES'
       , count(*) as Rows
       , sum(A) as A
       , sum(B) as B
       , sum(C) as C
from (
       select   Device
              , max(cast(A as int)) as A
              , max(cast(B as int)) as B
              , max(cast(C as int)) as C
       from T
       group by Device
) as A

整个汇总/立方体事物总是一场特殊的灾难。如果你从它的细节中受益,那就好了,使用它,否则我建议给它一个宽阔的铺位。没有你的解释,我无法理解你的查询;相比之下,我敢说,我的前两部分很容易理解而没有解释。

您可以创建三个UNION组件中每个组件的视图,并以其他有趣的方式排列它们(除了One Big Query之外)。

  

任何人都可以演示如何使用单个SELECT来获得这些结果吗?

您的查询和我的 单个SELECT语句; UNIONSELECT的一部分。我认为你的意思是,可以在没有UNION的情况下完成,答案是否定的。或者,也许“是的,但你不会喜欢它”。正如您自己提出的那样,您希望以两种不同的方式总结数据。这两种方式逻辑上不同:by customer和flag。 UNION是连接两个关系的关系代数运算符,这正是你所要求的! :-)

SQL Server也支持OVER clause;它允许更复杂的分组,并且您可以在没有UNION的情况下获得所需的结果。但是我怀疑SQL会像你到目前为止那样容易理解和改变,或者很少。