编程后端开发工程师,BI分析师

如何在SQL中实现具有唯一条件的可靠聚合(conditional aggregation),以构建带有多个过滤器的报告?在混合使用HAVING、CASE和聚合函数时存在哪些细节?

用 Hintsage AI 助手通过面试

答复。

条件聚合是报告中的经典问题。最初,为了计算不同的指标,会针对每个指标创建单独的查询和过滤器。不久之后,出现了一种更紧凑的解决方案——在聚合函数内使用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;

关键特性:

  • 无论WHERE过滤器如何,所有所需的总和都在一个查询中计算。
  • 在SUM内的CASE允许构建复杂的多指标报告。
  • HAVING应用于已经聚合的数据,用于对分组结果进行后过滤。

具有欺骗性的提问。

如果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进行。

常见错误和反模式

  • 缺少ELSE,CASE返回NULL,最终结果不正确。
  • 混合使用WHERE和HAVING,导致得到错误的行。
  • 使用多个查询而不是单个包含CASE的查询。

现实中的例子

负面案例

在分析报告中使用:

SUM(CASE WHEN status = 'approved' THEN 1 END)

出现了很多NULL,最终总和被低估。由于WHERE过滤器,部分所需行丢失。

优点:

  • 代码简洁。

缺点:

  • 结果不正确,报告错误地解释给业务方。

正面案例

使用:

SUM(CASE WHEN status = 'approved' THEN 1 ELSE 0 END)

代码保持在单个查询中,对总计的过滤通过HAVING进行。

优点:

  • 正确、透明的指标。
  • 容易添加新状态。

缺点:

  • 查询变得更长,对过滤器的准确性要求更高。