条件聚合 在需要在一个查询中根据不同条件聚合值(例如总和或数量)时使用。历史上,为了达到类似目的,SQL 开发者不得不编写多个子查询或针对每个类别单独进行连接和分组,这导致代码不够可读且性能较低。
问题在于同时计算多个具有不同条件的聚合是困难的 — 每个单独的聚合通常需要过滤,而简单的应用 SUM() 或 COUNT() 并不考虑聚合函数内部所需的条件。
解决方案 — 在聚合函数中使用 CASE 结构,这样可以在不进行多个连接的情况下“分隔”不同条件下的聚合:
代码示例:
SELECT department, SUM(CASE WHEN status = 'approved' THEN amount ELSE 0 END) AS approved_sum, SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) AS pending_sum, COUNT(CASE WHEN status = 'rejected' THEN 1 END) AS rejected_count FROM payments GROUP BY department;
关键特点:
是否可以在条件聚合中不使用 CASE 结构?
不正确的答案是直接在查询中使用 WHERE 与聚合函数一起。实际上,WHERE 在聚合之前过滤行,而不是在每个聚合列内部。
代码示例(错误方式):
SELECT COUNT(*) FROM payments WHERE status = 'approved'; SELECT COUNT(*) FROM payments WHERE status = 'pending';
这些查询不能在不同条件下粘合成一行结果而不使用 CASE。
如果在条件表达式中使用 NULL,会发生什么?
如果 CASE 不返回替代值,则默认情况下它会为 NULL,而聚合函数会忽略 NULL。
代码示例:
SUM(CASE WHEN status = 'approved' THEN amount END) -- 如果状态不是 'approved',则为 NULL,导致在 SUM 中忽略该行
可以使用 IF 来替代 CASE 吗?
在某些 SQL 方言中(例如,MySQL),这是可能的,但这种代码在不同数据库之间的可移植性较差。在通用查询中始终使用 CASE。
分析师试图通过编写多个单独的子查询来按每个状态计算总和。外部报告变得复杂,添加新状态每次都需要重写代码。
优点:
开发者使用 CASE 在一个通用查询中,创建了一个可以扩展的新状态的通用报告,简单编辑一个查询即可。
优点: