条件聚合是报告中的经典问题。最初,为了计算不同的指标,会针对每个指标创建单独的查询和过滤器。不久之后,出现了一种更紧凑的解决方案——在聚合函数内使用CASE进行条件聚合(例如,SUM(CASE WHEN ...))。当结合过滤器、分组和总计标题时,问题显现:很容易得到不正确的总和或错误地解释结果。
解决方案:在聚合函数内使用条件聚合。例如,需要按所有员工输出“处理中”和“完成”的订单数量:
SELECT employee_id, SUM(CASE WHEN status = 'processing' THEN 1 ELSE 0 END) as processing_count, SUM(CASE WHEN status = 'done' THEN 1 ELSE 0 END) as done_count FROM Orders GROUP BY employee_id;
关键特性:
如果CASE条件返回NULL而不是0,会发生什么?
聚合函数SUM会忽略NULL。因此,如果写CASE WHEN ... THEN 1 END,被跳过的行将不会被计算。最好总是显式指定ELSE 0。
SUM(CASE WHEN status = 'processing' THEN 1 ELSE 0 END)
在条件聚合中,WHERE过滤器是否会改变基于状态的最终总和?
是的:如果主要的WHERE限制了选择(例如,WHERE region = 'west'),那么计算只会在筛选后的数据上进行。对于全局总和,请使用子查询或移除过滤器。
可以使用HAVING在分组之前过滤行吗?
不可以。HAVING用于过滤已经分组的数据,原始行的过滤通过WHERE进行。
在分析报告中使用:
SUM(CASE WHEN status = 'approved' THEN 1 END)
出现了很多NULL,最终总和被低估。由于WHERE过滤器,部分所需行丢失。
优点:
缺点:
使用:
SUM(CASE WHEN status = 'approved' THEN 1 ELSE 0 END)
代码保持在单个查询中,对总计的过滤通过HAVING进行。
优点:
缺点: