如何在SQL中生成“空”聚合结果

我正在尝试优化SQL查询以使我的报告看起来更好.我的查询从一个表读取数据,按几个列分组,并计算一些聚合字段(计数和总和).
SELECT A,B,C,COUNT(*),SUM(D) FROM T
GROUP BY A,C
ORDER BY A,C

现在,我们假设B和C列是一些定义的常量字符串,例如,
B可以是’B1’或’B2′,C可以是’C1’或’C2′.因此,示例结果集是:

A  | B  | C  | COUNT(*) | SUM(D)
--------------------------------
A1 | B1 | C1 |       34 |   1752
A1 | B1 | C2 |        4 |    183
A1 | B2 | C1 |      199 |   8926
A1 | B2 | C2 |       56 |   2511
A2 | B1 | C2 |        6 |     89
A2 | B2 | C2 |       12 |    231
A3 | B1 | C1 |       89 |    552
...

正如你所看到的,对于’A1′,我有四种可能的(B,C)组合,但对于’A2’则不然.我的问题是:如何在给定的表中生成(B,C)组合不存在的摘要行?也就是说,我如何打印,这些行:

A  | B  | C  | COUNT(*) | SUM(D)
--------------------------------
A2 | B1 | C1 |        0 |      0
A2 | B2 | C1 |        0 |      0

我能看到的唯一解决方案是创建一些包含所有(B,C)值的辅助表,然后使用该aux表进行RIGHT OUTER JOIN.但我正在寻找一种更清洁的方式……

谢谢你们.

解决方法

辅助表不必是真正的表,它可以是公用表表达式 – 至少如果您可以从表本身获取所有可能的值(或您感兴趣的所有值).使用@Bob Jarvis’查询生成所有可能的组合,您可以执行以下操作:
WITH CTE AS (
    SELECT * FROM (SELECT DISTINCT a FROM T)
    JOIN (SELECT DISTINCT b,c FROM T) ON (1 = 1)
)
SELECT CTE.A,CTE.B,CTE.C,SUM(CASE WHEN T.A IS NULL THEN 0 ELSE 1 END),NVL(SUM(T.D),0)
FROM CTE
LEFT JOIN T ON T.A = CTE.A AND T.B = CTE.B AND T.C = CTE.C
GROUP BY CTE.A,CTE.C
ORDER BY CTE.A,CTE.C;

如果你有固定值可能不在表中,那么它会更复杂(或者更丑陋,并且随着更多可能的值而变得更糟):

WITH CTE AS (
    SELECT * FROM (SELECT DISTINCT a FROM T)
    JOIN (SELECT 'B1' AS B FROM DUAL
        UNION ALL SELECT 'B2' FROM DUAL) ON (1 = 1)
    JOIN (SELECT 'C1' AS C FROM DUAL
        UNION ALL SELECT 'C2' FROM DUAL) ON (1 = 1)
)
SELECT CTE.A,CTE.C;

但你必须加入一些了解“缺失”价值观的东西.如果在其他地方需要相同的逻辑,并且您有固定的值,那么永久表可能更清晰 – 当然,可能需要维护.您还可以将流水线函数视为代理表,但可能依赖于卷.

相关文章

(一)日志传送架构 (1.1)相关服务器 主服务器 :用于生产的服务器,上面运行这生产SQL Server数据库...
(一)事故背景 最近在SQL Server 2012生产数据库上配置完事物复制(发布订阅)后,生产数据库业务出现了...
(一)测试目的 目前公司使用的SQL SERVER 2012高可用环境为主备模式,其中主库可执行读写操作,备库既...
(一)背景个人在使用sql server时,用到了sql server的发布订阅来做主从同步,类似MySQL的异步复制。在...
UNION和OR谓词 找出 product 和 product2 中售价高于 500 的商品的基本信息. select * from product wh...
datawhale组队学习task03