【问题标题】:Summarize data in two different ways以两种不同的方式汇总数据
【发布时间】:2016-09-23 22:42:57
【问题描述】:

假设我有一个存储客户姓名、设备编号和一些标志的表。一些示例数据如下所示:

[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 MSDNROLLUP 支持多个分组,但我不知道如何让它产生我想要的结果。谁能演示如何使用单个 SELECT 来获得这些结果?

【问题讨论】:

  • 分组、汇总和多维数据集是分层的,但您想要的输出不是。你所做的是获得你想要的结果的唯一方法:)
  • @P.Salmon 这就是我所害怕的,但我一直在想,如果我像在第二个 SELECT 中那样使用双重聚合,那么它是可能的。
  • 有一些方法可以让你把它变成一个“单一”查询(即不使用UNION),但它们都将涉及比你更复杂/更难理解/性能更低的代码已经有了。如果您真的想要一个,或者您可以接受@P.Salmon 基本上是一击毙命,我可以稍后再发布一个示例。

标签: sql sql-server tsql cube rollup


【解决方案1】:

我需要一份同时呈现 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 组件中的每一个的视图,并以其他有趣的方式排列它们(除了一个大查询)。

谁能演示如何使用单个 SELECT 来获得这些结果?

您的查询和我的查询都是单一的SELECT 语句; UNIONSELECT 的一部分。我认为你的意思是,如果没有UNION,它可以完成吗?答案是否定的。或者,也许“是的,但你不会喜欢它”。当您自己提出问题时,您想以两种不同的方式总结数据。这两种方式逻辑上不同:按客户和按标志。 UNION 是连接两个关系的关系代数运算符,这正是您所要求的! :-)

SQL server 也支持OVER clause;它允许更复杂的分组类型,并且您可以在没有UNION 的情况下使其产生所需的结果。但我怀疑 SQL 是否会像您目前所拥有的那样易于理解和更改,或者只需要几行代码。

【讨论】:

    猜你喜欢
    • 2018-02-24
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多