CASE WHEN 在 SQL 里有两种写法:一种是简单 CASE,只支持等值判断,连 >、IS NULL 都写不进去;另一种是搜索 CASE,支持任意布尔表达式。实际工作中,几乎全用后者——业务逻辑哪有那么多“等于”就完事的?

但 CASE WHEN 真不是万能开关。嵌套过深或者漏写 ELSE,会直接让 NULL 值混入结果,尤其在聚合、JOIN 的场景下,静默出错比报错更头疼。
CASE WHEN 的两种写法区别在哪?
简单 CASE(CASE column WHEN value THEN ...)本质上就是个 switch 语句,只能做等值匹配。想用 >、IS NULL 或者函数?没门。搜索 CASE(CASE WHEN condition THEN ...)才是真正的条件表达式,所有布尔判断都能往里扔。
实际开发中,简单 CASE 基本是个摆设。比如判断用户等级,分数区间怎么可能是等值?
SELECT
name,
CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B'
WHEN score >= 60 THEN 'C'
ELSE 'F'
END AS grade
FROM users;
- 漏写
ELSE:不满足任何条件时返回的是NULL,不是空字符串,也不是 0。 WHEN子句按顺序执行,碰到第一个为 true 的就停了,后面的不判断——别把顺序搞反。- 所有
THEN返回值类型尽量一致,否则数据库可能悄悄做隐式转换,把字符串和数字混用会出警告甚至截断。
在 GROUP BY 或聚合函数里怎么安全用 CASE WHEN?
常见错误:在 SELECT 里写着 CASE,却想按分类统计,结果 GROUP BY 没跟上。分组依据必须和聚合逻辑对齐——要么在 GROUP BY 里复写相同表达式,要么确认数据库支持列别名(MySQL 8.0+、PostgreSQL 可以,SQLite 和旧版 MySQL 不行)。
比如统计各年龄段用户数:
SELECT
CASE
WHEN age < 18 THEN 'under_18'
WHEN age BETWEEN 18 AND 35 THEN 'young_adult'
ELSE 'senior'
END AS age_group,
COUNT(*) AS cnt
FROM users
GROUP BY
CASE
WHEN age < 18 THEN 'under_18'
WHEN age BETWEEN 18 AND 35 THEN 'young_adult'
ELSE 'senior'
END;
- 如果
CASE里用了不可索引的函数(比如UPPER(name)),GROUP BY 的性能会受影响,数据量大时尤其明显。 - 聚合中嵌套 CASE 时,比如
SUM(CASE ...),一定记得写ELSE 0。否则 SUM 会跳过 NULL,结果偏小——你以为是 0,其实不是。
为什么在 WHERE 或 ON 条件里少用 CASE WHEN?
WHERE 子句的本质是过滤,而 CASE WHEN 是个表达式计算。它没法走索引,还可能让优化器放弃执行计划缓存。一句话:能用 AND/OR 搞定,就别用 CASE。
比如“VIP 用户或下单超 5 次的普通用户”:
WHERE
CASE
WHEN user_type = 'vip' THEN 1
WHEN order_count > 5 THEN 1
ELSE 0
END = 1
不如直接写:
WHERE user_type = 'vip' OR order_count > 5
- 前者强制全表扫描,后者可能走
user_type或order_count的索引。 - ON 子句里同理——JOIN 条件里塞 CASE,连接变慢还不好调试。
- 如果真需要动态条件(比如多租户字段名不同),优先在应用层拼 SQL 或者用 UNION 拆开,别硬塞 CASE。
最后说个最容易被忽略的点:NULL 处理。所有分支都没命中时,默认返回 NULL。而 NULL 在 COUNT、SUM、JOIN 关联里的行为很特殊——不报错,但结果会偏离预期。写完 CASE 后,先用 WHERE result_column IS NULL 筛一遍,比上线后再排查数据异常快得多。
