SQL 中 CASE WHEN 怎么用?常见场景有哪些?
简化版
CASE WHEN 是 SQL 里的条件表达式,可以在查询结果、排序、聚合统计和更新语句中按条件返回不同值;它按条件顺序匹配,命中后返回对应结果。
详细版
CASE WHEN 常见写法是:
CASE
WHEN condition1 THEN value1
WHEN condition2 THEN value2
ELSE default_value
END
它不是流程控制语句,而是表达式,因此可以放在 SELECT、ORDER BY、GROUP BY、HAVING、UPDATE SET 等位置。
典型场景包括:把状态码翻译成文案、按分数划等级、条件聚合统计、按业务优先级排序、批量更新不同值。面试时要强调 WHEN 顺序、ELSE 默认值、返回类型兼容,以及条件写在列上可能影响索引使用。
完整版教学
一、CASE WHEN 的本质是表达式
CASE WHEN 会根据条件返回一个值,所以它可以出现在需要“值”的位置。
SELECT
id,
score,
CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B'
WHEN score >= 60 THEN 'C'
ELSE 'D'
END AS grade
FROM exams;
如果 score=85,第一条条件不满足,第二条满足,结果是 B。它的结果像普通列一样可以命名为 grade。
记忆钩子:
CASE WHEN不是单独跑流程,而是在 SQL 里“算出一个值”。
二、两种写法:搜索 CASE 与简单 CASE
搜索 CASE 可以写任意布尔条件:
CASE
WHEN amount >= 1000 THEN 'large'
WHEN amount >= 100 THEN 'medium'
ELSE 'small'
END
简单 CASE 是拿一个表达式和多个值比较:
CASE status
WHEN 0 THEN 'pending'
WHEN 1 THEN 'paid'
WHEN 2 THEN 'shipped'
ELSE 'unknown'
END
| 类型 | 适合场景 | 特点 |
|---|---|---|
| 搜索 CASE | 范围判断、复合条件 | WHEN 后是条件 |
| 简单 CASE | 状态码枚举 | WHEN 后是匹配值 |
| 嵌套 CASE | 少量复杂分支 | 可读性容易下降 |
面试中多数复杂场景使用搜索 CASE,因为它能表达 >=、AND、OR 等条件。
三、条件顺序会影响结果
CASE WHEN 按顺序匹配,先命中的分支会返回结果,后面的分支不再决定最终值。
错误示例:
CASE
WHEN score >= 60 THEN 'pass'
WHEN score >= 90 THEN 'excellent'
ELSE 'fail'
END
score=95 时会先命中 score >= 60,结果是 pass,不会得到 excellent。
正确写法应把更具体、更严格的条件放前面:
CASE
WHEN score >= 90 THEN 'excellent'
WHEN score >= 60 THEN 'pass'
ELSE 'fail'
END
这类题考的是条件覆盖关系,而不是语法本身。
四、条件聚合是高频用法
面试和业务报表里经常需要“一次扫描统计多个指标”,CASE WHEN 可以和聚合函数配合。
SELECT
COUNT(*) AS total_orders,
SUM(CASE WHEN status = 'paid' THEN 1 ELSE 0 END) AS paid_orders,
SUM(CASE WHEN amount >= 1000 THEN 1 ELSE 0 END) AS large_orders
FROM orders;
如果有 1000 条订单,其中 700 条已支付、80 条金额不小于 1000,上面会返回:
total_orders | paid_orders | large_orders
1000 | 700 | 80
这种写法避免为了每个指标各查一遍表,在报表统计里很常见。
五、CASE WHEN 也能做业务排序
有些列表排序不是简单按时间或金额,而是按业务优先级。例如订单状态希望 paid 排前,其次 pending,最后 cancelled。
SELECT id, status, created_at
FROM orders
ORDER BY
CASE status
WHEN 'paid' THEN 1
WHEN 'pending' THEN 2
WHEN 'cancelled' THEN 3
ELSE 9
END,
created_at DESC;
排序权重可以画成:
paid -> 1
pending -> 2
cancelled -> 3
其他 -> 9
这个技巧常用于“置顶、推荐、处理中优先”等列表,但表达式排序可能无法直接利用普通索引,需要关注数据量和执行计划。
六、UPDATE 中的批量条件更新
CASE WHEN 还可以用于一次更新多种值。
UPDATE products
SET price = CASE
WHEN category = 'book' THEN price * 0.9
WHEN category = 'phone' THEN price * 0.95
ELSE price
END
WHERE category IN ('book', 'phone');
如果书籍价格 100,会变成 90;手机价格 2000,会变成 1900。ELSE price 用来确保不命中的行保持原值。
实际写更新语句时要格外注意 WHERE 范围,避免全表都被计算。面试回答时可以补一句:大批量更新要分批、备份、在事务里验证影响行数。
七、常见误区与追问
- 误区:
CASE WHEN是存储过程里的流程控制。 它在查询中是表达式,返回一个值。 - 误区:
WHEN顺序无所谓。 分支按顺序匹配,范围条件写错顺序会改变结果。 - 误区:可以省略
ELSE且没有影响。 没有命中任何分支时结果通常为NULL,可能影响展示和统计。 - 误区:
THEN返回什么类型都可以随便混。 各分支返回类型应兼容,否则可能隐式转换或报错。 - 追问:如何统计不同状态数量? 使用
SUM(CASE WHEN status = ... THEN 1 ELSE 0 END)做条件聚合。 - 追问:
CASE WHEN会影响索引吗? 放在过滤列或排序表达式上可能降低普通索引利用率,需要看执行计划。
八、加强记忆
把 CASE WHEN 当作 SQL 里的“条件算值器”:在 SELECT 里翻译字段,在聚合里统计指标,在 ORDER BY 里制造排序权重,在 UPDATE 里批量改不同值。写的时候盯住三件事:条件顺序、ELSE、返回类型。