CASE WHEN 是用于字段值转换、条件过滤和聚合统计的SQL表达式,支持SELECT、WHERE、ORDER BY等子句,但需注意ELSE缺失、类型一致性和索引失效等问题。

CASE WHEN 在 SELECT 中做字段值转换最常用
直接在查询结果里动态改值,比如把数字状态码转成中文描述,不用在应用层处理。关键点是 CASE WHEN 是表达式,能用在 SELECT、ORDER BY、HAVING 甚至 WHERE(但要小心性能)里。
常见错误:漏写 ELSE,结果为 NULL 却没意识到;或者把字符串值写成不带引号的标识符,报错 Unknown column 'xxx'。
-
WHEN后面是布尔表达式,不是列名匹配(除非写成CASE status WHEN 1 THEN ...这种简写形式) - 多个
WHEN条件按顺序匹配,遇到第一个为TRUE的就返回对应THEN值,后续不再判断 - 数值型和字符串型分支的
THEN返回值类型最好一致,否则 MySQL 会隐式转换,可能出意外(比如THEN 0和THEN '未知'混用,整列变成字符串)
SELECT
id,
name,
CASE status
WHEN 1 THEN '启用'
WHEN 0 THEN '禁用'
ELSE '其他'
END AS status_text
FROM users;
在 WHERE 子句中用 CASE WHEN 实现动态条件过滤
不是所有场景都适合——MySQL 无法对含 CASE WHEN 的表达式有效使用索引,容易全表扫描。只建议用于低频、小数据量或条件逻辑复杂到 AND/OR 难以清晰表达的情况。
典型误用:把本该用 OR 拆开的多条件,硬套进一个 CASE WHEN 里,导致执行计划变差。
- 必须确保
CASE WHEN整体返回布尔值(即TRUE/FALSE或1/0),例如CASE WHEN type = 'A' THEN created_at > '2023-01-01' ELSE updated_at > '2023-01-01' END - 更安全的写法是用逻辑运算组合:
(type = 'A' AND created_at > '2023-01-01') OR (type != 'A' AND updated_at > '2023-01-01') - 如果非要用,记得加括号明确优先级,避免被解析成
CASE WHEN (type = 'A' AND created_at > ...) OR ...
聚合统计时配合 COUNT/SUM 做条件计数
这是 CASE WHEN 最高效、最推荐的用法之一。比子查询或多次 JOIN 轻量,且 MySQL 能较好优化。
容易忽略的点:在 SUM 里用 CASE WHEN 返回 0/1,比用 COUNT 更灵活(比如支持加权统计);但若漏写 ELSE 0,NULL 不参与 SUM 计算,结果偏小。
-
COUNT(CASE WHEN status = 1 THEN 1 END)和SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END)效果一样,但前者更语义清晰 - 想统计「启用且近7天登录过」的人数:
COUNT(CASE WHEN status = 1 AND last_login > DATE_SUB(NOW(), INTERVAL 7 DAY) THEN 1 END) - 避免写成
COUNT(CASE WHEN ... THEN id END)——万一id本身为NULL,会被忽略
SELECT COUNT(*) AS total, COUNT(CASE WHEN status = 1 THEN 1 END) AS active_count, AVG(CASE WHEN amount > 100 THEN amount END) AS avg_high_amount FROM orders;
嵌套 CASE WHEN 容易引发可读性与维护问题
两层以内还行,三层起就要警惕。调试困难、修改风险高,而且 MySQL 对深层嵌套没有额外优化,纯靠解释器逐层展开。
真实项目里,一旦看到 CASE WHEN ... WHEN ... ELSE CASE WHEN ... END END,基本说明业务规则已超出 SQL 承载能力,该抽到应用层或用查找表替代。
- 先检查是否真需要嵌套:很多“嵌套”其实是逻辑拆分问题,比如用两个独立的
CASE字段更清楚 - 别在
ORDER BY里嵌套太深,排序性能会明显下降 - 用空格和换行对齐
WHEN/THEN/ELSE,否则 review 时极易看串行
CASE WHEN,就让它只干一件事:转换、过滤或统计,别堆逻辑。越靠近业务规则中心的地方,越容易因一个小改动引发整条 SQL 行为偏移。










