应使用SUM(CASE WHEN ...)在聚合函数内按条件求和,必须写ELSE 0防NULL,多条件用并列分支;PostgreSQL可用FILTER子句替代,更简洁安全。

WHERE 和 HAVING 都不能直接解决“分组内条件求和”
想在 SUM 里只加满足某条件的行,但又不能丢掉其他行(比如要保留该分组的总记录数),这时候用 WHERE 会整个过滤掉不满足条件的行,HAVING 又只能筛分组结果——两者都动不了“分组内按条件聚合”的需求。
真正该用的是表达式级条件控制,也就是在聚合函数内部做判断。
-
CASE WHEN必须写在SUM()里面,不是外面 - 漏写
ELSE 0很容易导致部分结果为NULL,进而让整列SUM变成NULL - 条件字段如果可能为
NULL,= 'xxx'不会匹配,得用IS NOT DISTINCT FROM或显式判断IS NULL
SUM(CASE WHEN ...) 的标准写法和常见翻车点
核心就一条:把条件逻辑塞进聚合函数参数里,让每行先算出“该加多少”,再汇总。
比如统计每个部门中「职级为 Senior」的人薪资总和,同时保留部门总人数:
SELECT dept,
COUNT(*) AS total_cnt,
SUM(CASE WHEN level = 'Senior' THEN salary ELSE 0 END) AS senior_salary_sum
FROM employees
GROUP BY dept;
- 必须写
ELSE 0,写ELSE NULL或不写ELSE,会导致该行贡献NULL,而SUM(NULL, 1000)=1000,但SUM(NULL, NULL)=NULL -
level = 'Senior'对NULL值永远返回FALSE,不会进THEN分支;如果业务上想把NULL当作某种默认职级,得额外加OR level IS NULL - 别在
CASE外套一层COALESCE(SUM(...), 0)来“防 NULL”——这是本末倒置,问题出在CASE没兜底
多个条件叠加时,CASE WHEN 的嵌套 vs 并列写法
要同时统计 Senior、Junior、Intern 三类薪资总和?别嵌套 CASE,用并列分支更清晰、性能也更好。
错误示范(嵌套,难读且易错):
SUM(CASE WHEN level = 'Senior' THEN salary ELSE CASE WHEN level = 'Junior' THEN salary ELSE 0 END END)
正确做法(三个独立 CASE):
SELECT dept,
SUM(CASE WHEN level = 'Senior' THEN salary ELSE 0 END) AS senior_sum,
SUM(CASE WHEN level = 'Junior' THEN salary ELSE 0 END) AS junior_sum,
SUM(CASE WHEN level = 'Intern' THEN salary ELSE 0 END) AS intern_sum
FROM employees
GROUP BY dept;
- 每个
SUM独立计算,互不影响;数据库优化器也能更好并行处理 - 如果某行
level是NULL,三个分支都走ELSE 0,结果干净 - 别试图用一个
CASE返回字符串再用SUM去加——类型不匹配直接报错:SUM('abc')不合法
替代方案:FILTER 子句(PostgreSQL 9.4+)
如果你用的是 PostgreSQL,FILTER 是更简洁、语义更明确的写法,功能等价于 SUM(CASE WHEN ...),但不易写错。
SELECT dept,
SUM(salary) FILTER (WHERE level = 'Senior') AS senior_salary_sum
FROM employees
GROUP BY dept;
- 不需要手动写
ELSE 0,没匹配的行自动忽略,SUM对空集返回0 - MySQL、SQL Server、Oracle 都不支持
FILTER,强行用会报错:ERROR: syntax error at or near "FILTER" - 某些旧版 PostgreSQL(如 9.3)也不支持,查版本用
SELECT version();
跨数据库兼容性要求高时,还是老实用 CASE WHEN;只跑 PostgreSQL 且版本够新,FILTER 能少写一半容易出错的样板代码。

















