COUNT+WHERE无法替代SUM(CASE WHEN),因其只能单条件全局过滤,无法并行统计多条件;后者每行判断后累加,支持多条件聚合,且需注意ELSE 0不可省、勿用COUNT(CASE)、条件顺序影响匹配结果。

为什么直接用 COUNT + WHERE 不能替代 SUM(CASE WHEN)
因为 COUNT 配合 WHERE 只能做单条件全局过滤,无法在同一个 SELECT 中并行统计多个互斥或重叠的条件。比如要同时算「订单金额 > 100 的数量」和「订单状态 = 'shipped' 的数量」,用多个 WHERE 就得写三张表 JOIN 或三个子查询——性能差、可读性低。SUM(CASE WHEN ... THEN 1 ELSE 0 END) 则是在每行上做逻辑判断后累加,天然支持多条件并行聚合。
SUM(CASE WHEN) 的标准写法与常见错误
核心结构是:SUM(CASE WHEN condition THEN 1 ELSE 0 END)。注意三点:
-
ELSE 0不能省略:如果漏掉,NULL值不参与SUM计算,会导致结果偏小(例如某行不满足任何WHEN,就变成NULL,而SUM(NULL, 1, 1)= 2,但SUM(NULL, 1, 1)实际等于 2 —— 等等,这里容易误判:其实SUM会自动忽略NULL,所以没ELSE时,不匹配的行相当于加了NULL,不计入,结果反而“看起来对”,但逻辑不清晰、易被后续修改破坏) - 别用
COUNT(CASE WHEN ...):虽然语法合法,但COUNT会把NULL当作不计数项,而COUNT(1)和COUNT(*)行为不同,容易混淆;统一用SUM+0/1最直观可靠 - 条件顺序影响结果:多个
WHEN是从上到下匹配,第一个为真即终止,所以范围宽的条件(如amount > 0)要放在窄条件(如amount > 1000)之后,否则大条件永远截断小条件
处理 NULL 值和边界场景的实际技巧
真实数据常含 NULL,比如 status 字段为空。此时直接写 CASE WHEN status = 'paid' THEN 1 ELSE 0 END 会让 status IS NULL 的行进 ELSE 分支,算作 0 —— 这通常符合预期。但如果想单独统计 NULL,就得显式写出:
SUM(CASE WHEN status IS NULL THEN 1 ELSE 0 END) AS null_count, SUM(CASE WHEN status = 'paid' THEN 1 ELSE 0 END) AS paid_count
另外,数值比较要防隐式转换:比如 score 是字符串类型,CASE WHEN score > 90 THEN 1... 可能按字典序比('100' CAST(score AS INT) 或确保字段类型正确。
MySQL / PostgreSQL / SQL Server 在语法上的细微差别
基础语法一致,但有两处要注意:
- PostgreSQL 不允许
THEN后跟无类型的字面量:写THEN 1没问题,但THEN 'true'在某些上下文中可能报错,建议统一用数字或显式类型转换,如THEN 'true'::TEXT - SQL Server 对
CASE表达式返回类型推导更严格:如果一个分支是INT,另一个是VARCHAR,会强制转成VARCHAR,导致SUM失败;务必保证所有THEN和ELSE返回同类型,推荐全用INT - MySQL 8.0+ 支持窗口版
SUM(CASE ...),可用于分组内占比计算,如SUM(CASE WHEN paid=1 THEN 1 ELSE 0 END) / COUNT(*) OVER(PARTITION BY region)
跨数据库移植时,最安全的做法是始终用 INT 做分支值,并显式写 ELSE 0。

















