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 行为偏移。
