case when是sql标准条件表达式,非函数也非控制流语句,必须嵌入select、where等子句使用;需注意类型一致、显式else、顺序匹配及索引失效风险。

CASE WHEN 的本质是表达式,不是控制流语句。它必须出现在 SELECT、WHERE、ORDER BY、GROUP BY 等允许表达式的位置,不能单独执行,也不能嵌套在 INSERT INTO ... VALUES(...) 的值列表里直接当语句用。
WHERE 子句中用 CASE WHEN 做动态条件过滤
很多人想根据某个字段值决定用不同条件过滤,比如「状态为 draft 时只查创建时间 > 7 天的记录,否则查所有」。但 CASE WHEN 在 WHERE 中不能直接返回布尔值——它只能返回值,所以得配合比较操作符。
- ✅ 正确写法:把逻辑拆成 OR 分支,或用
CASE WHEN返回统一类型再比较,例如:WHERE (status = 'draft' AND created_at
- ❌ 错误写法:
WHERE CASE WHEN status = 'draft' THEN created_at (PostgreSQL 报错:<code>CASE</code> 分支类型不一致;MySQL 可能隐式转为 0/1,但语义模糊且不可靠)
- ⚠️ 注意:部分数据库(如 SQL Server)支持在
WHERE里用CASE返回 1/0 再跟= 1,但可读性差,跨库迁移风险高
SELECT 中用 CASE WHEN 做字段值映射(最常用场景)
这是 CASE WHEN 最稳妥、最无争议的用法:对查询结果做即时转换,比如把数字状态码转成中文、按金额分段打标签。
- 推荐用简单
CASE(而非搜索CASE)当匹配字段值固定且不多时:CASE status WHEN 1 THEN '待审核' WHEN 2 THEN '已通过' ELSE '已拒绝' END AS status_label
- 复杂条件必须用搜索
CASE:CASE WHEN amount >= 10000 THEN '大额' WHEN amount >= 1000 THEN '中等' ELSE '小额' END AS amount_level
- ⚠️ 容易漏掉
ELSE:没写ELSE时默认返回NULL,可能导致前端展示空值或聚合出错(比如COUNT(status_label)少计数) - ⚠️ 类型要一致:所有
THEN和ELSE返回值必须兼容同一数据类型,否则数据库会尝试隐式转换(如把字符串和数字混用可能报错或截断)
ORDER BY 和 GROUP BY 中用 CASE WHEN 实现自定义排序/分组
需要按业务逻辑而非字典序排优先级(如「紧急 > 高 > 中 > 低」),或按区间分组统计时,CASE WHEN 是刚需。
- 自定义排序示例(MySQL/PostgreSQL 都支持):
ORDER BY CASE priority WHEN '紧急' THEN 1 WHEN '高' THEN 2 WHEN '中' THEN 3 ELSE 4 END
- 分组统计示例:
GROUP BY CASE WHEN score >= 90 THEN 'A' WHEN score >= 80 THEN 'B' ELSE 'C' END
- ⚠️ 注意:如果
SELECT列表里用了CASE WHEN表达式,而GROUP BY想按它分组,必须重复写一遍表达式,或用列别名(仅 PostgreSQL 支持GROUP BY 1或别名,MySQL 8.0+ 支持别名,但旧版不支持) - ⚠️ 性能影响:在
ORDER BY或GROUP BY里用CASE无法利用索引,大数据量时可能显著变慢
真正容易被忽略的是 CASE WHEN 的求值顺序:从上到下、一旦匹配就终止,不会继续检查后续分支。这意味着条件排列顺序直接影响结果——比如把 amount > 100 放在 amount > 50 前面,后者永远不生效。写的时候得按范围从细到粗、或按优先级从高到低排。










