case when 是 sql 标准的 if-else 语法,非函数,必须用 end 结尾;分搜索型(支持任意布尔表达式)和简单型(仅等值匹配,不处理 null);条件顺序执行、需显式 else、各分支返回值类型必须兼容。

CASE WHEN 就是 SQL 里的 if-else,但写法和语义更严格,不能直接套用编程语言的 IF 逻辑
为什么 CASE WHEN 不能照搬 IF 的写法?
SQL 没有 IF 表达式(部分方言如 MySQL 支持 IF() 函数,但非标准且不支持多分支),CASE WHEN 是唯一标准、可移植的条件表达式。它分两种形式:CASE WHEN ... THEN ... END(搜索型)和 CASE column WHEN value THEN ... END(简单型),后者只支持等值判断,灵活性差。
常见错误是把多个独立条件写成嵌套 IF 风格,结果漏掉 ELSE 导致 NULL,或条件顺序错乱导致逻辑覆盖——比如把范围更大的条件(如 score >= 0)写在前面,后面更具体的分支(如 score >= 90)永远不生效。
- 必须显式写
ELSE,否则不满足任何WHEN时返回NULL - 条件按书写顺序从上到下匹配,第一个为
TRUE的分支即终止执行 - 所有
THEN后的表达式必须类型兼容(例如不能一会儿返回INT,一会儿返回VARCHAR)
如何安全地把多层 IF 转成 CASE WHEN?
核心是把每个 IF 分支拆成一个 WHEN 子句,并确保条件互斥、覆盖完整。尤其注意边界处理(比如 还是 <code>)、空值(<code>NULL 不参与任何比较,需用 IS NULL 单独判断)。
示例:把“如果 score ≥ 90 → A;80 ≤ score
SELECT name,
CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B' -- 注意:这里隐含 score = 60 THEN 'C'
ELSE 'F'
END AS grade
FROM students;
- 不需要写
score ,靠执行顺序自然保证 - 用
ELSE涵盖所有剩余情况(包括score IS NULL) - 若需单独处理 NULL,加一行
WHEN score IS NULL THEN 'N/A'并放在最前或最后,视业务而定
CASE WHEN 在 WHERE / ORDER BY / GROUP BY 中怎么用?
它不是只能出现在 SELECT 列表里。在 WHERE 中可用于动态过滤,在 ORDER BY 中可实现自定义排序优先级,在 GROUP BY 中能按计算分组——但要注意:这些位置只允许**确定性表达式**,不能调用随机函数或依赖行外状态。
常见误用:
- 在
WHERE中写CASE WHEN flag = 1 THEN id IN (1,2,3) ELSE id IN (4,5)——语法错误,CASE返回值不能是布尔表达式,应改写为(flag = 1 AND id IN (1,2,3)) OR (flag != 1 AND id IN (4,5)) - 在
ORDER BY中用CASE WHEN status = 'done' THEN 1 ELSE 2 END是安全的,但若引用了聚合函数又没加GROUP BY,会报错 - 在
GROUP BY中用CASE WHEN amount > 1000 THEN 'high' ELSE 'low'可以,但该表达式必须和SELECT中的完全一致(某些数据库如 PostgreSQL 要求严格匹配)
性能和可读性陷阱有哪些?
CASE WHEN 本身无性能损耗,但滥用会导致执行计划变差:比如在大表 WHERE 中对字段做函数式判断(CASE WHEN UPPER(name) = 'JOHN' THEN ...),会阻止索引使用;或者在 SELECT 中嵌套过深(超过 5–6 层),让执行引擎难以优化分支预测。
- 避免在
WHERE中对列使用函数包装后再进CASE,尽量把逻辑前置到列上 - 超过 4 个分支时,考虑是否该抽成查找表(
lookup_grade)并JOIN,更易维护 - 别在
CASE里调用子查询或标量函数(如(SELECT COUNT(*) FROM log WHERE log.id = t.id)),这会让每行都触发一次执行
最常被忽略的是:CASE 表达式的结果列默认无名,若用于后续计算或导出,记得用 AS 显式命名,否则可能在某些客户端或 ORM 中引发取值失败。










