应优先使用 sum(case when ... then 1 else 0 end) 替代 count(case when),以避免 null 处理歧义、类型转换错误;需显式处理空值与 null;多维度统计时直接在外层 group by;嵌套 case when 需按从高到低顺序书写。

直接用 SUM(CASE WHEN) 而不是 COUNT(CASE WHEN)
多数人第一反应是 COUNT(CASE WHEN status = 'paid' THEN 1 END),但这样写有隐患:当某行不满足条件时,CASE 返回 NULL,而 COUNT 会跳过 NULL —— 看似没问题,实则语义模糊、类型易出错。更稳妥的做法是统一用 SUM(CASE WHEN ... THEN 1 ELSE 0 END)。
-
SUM对0和NULL的处理更可预测:加0不影响结果,加NULL会被忽略,但显式写ELSE 0就彻底规避歧义 - 所有分支返回数值类型(
INT),避免数据库因隐式转换报错,比如 Oracle 或 older PostgreSQL 可能警告 “inconsistent datatype” - 和金额类字段(如
amount)共用同一模式:SUM(CASE WHEN status='paid' THEN amount ELSE 0 END),结构一致,不易漏写ELSE
分类字段含 NULL 或空字符串时必须显式覆盖
如果 status 列存在 NULL 或 '',像 CASE WHEN status = 'paid' THEN 1 ELSE 0 END 会把这部分数据全归到 ELSE 0,看起来“统计了”,但你无法区分是“非 paid”还是“数据缺失”。真实业务中这常导致漏统或误判。
- 正确做法是把空值单独列出来:
CASE WHEN status = 'paid' THEN 1 WHEN status IS NULL THEN 0 WHEN status = '' THEN 0 ELSE 0 END,或更清晰地拆成独立指标 - 更推荐方式:用额外一列统计异常值,例如
SUM(CASE WHEN status IS NULL OR status = '' THEN 1 ELSE 0 END) AS unknown_status_count - 别依赖
ELSE“兜底”——它掩盖问题;明确写出每种可能状态,才是可维护的写法
多维度横向切片时,GROUP BY 可省略
想按区域统计“高/中/低销量订单数”,很多人习惯先 GROUP BY region 再套子查询。其实完全不需要:只要最终目标是一行一个区域,直接在最外层 GROUP BY region 即可,CASE WHEN 在聚合内部做横向分片,不干扰分组逻辑。
- 错误写法:把
CASE WHEN放进子查询再JOIN,性能差、可读性低、容易丢行 - 正确结构:
SELECT region, SUM(CASE WHEN amount > 5000 THEN 1 ELSE 0 END) AS high_cnt, ... FROM sales GROUP BY region - 注意:一旦用了
GROUP BY,所有非聚合字段(如region)必须出现在GROUP BY中,否则 MySQL 5.7+ 或 strict mode 下直接报ERROR 1140
嵌套 CASE WHEN 容易踩顺序陷阱
CASE WHEN 按书写顺序匹配,遇到第一个为真就返回,后续分支不再判断。这点和编程里的 if-else if-else 一样,但 SQL 里更容易被忽略。
- 比如写
CASE WHEN amount >= 2000 THEN '中' WHEN amount >= 5000 THEN '高',永远得不到 “高”——因为 >=2000 已命中 - 正确顺序必须从高到低:
WHEN amount >= 5000 THEN '高' WHEN amount >= 2000 THEN '中' ELSE '低' - 区间判断慎用
BETWEEN:它包含边界,amount BETWEEN 2000 AND 5000和amount > 5000之间有缝隙,建议统一用>=/显式定义开闭区间
ELSE 分支和 GROUP BY 覆盖范围,比调半天执行计划更省时间。










