CASE 就是 SQL 的 if/else
CASE 是在查询中加入条件逻辑的方式。它按顺序检查各个 WHEN 分支,选出第一个匹配的分支,返回 THEN 后面的值。如果没有分支匹配,就返回 ELSE 的值;如果你没写 ELSE,就返回 NULL。
关键词是表达式。CASE 产生一个值,所以凡是可以放值的地方都能用它:SELECT 的一列、ORDER BY 的排序键、比较运算的右侧、函数的参数。
完整的结构就是这样:CASE,一个或多个 WHEN ... THEN ...,可选的 ELSE,最后是 END。END 是必须的,忘了写它是最常见的笔误。
一个实际的例子
假设你有一张订单表,想按金额大小给每一行打上标签。先在行内建一张小表,这样你就能运行这条查询:
分支从上往下检查。第一个匹配的分支胜出,所以要按从最具体到最笼统的顺序排列。ELSE 兜住所有没匹配上的情况:如果没有它,1200.00 返回的会是 NULL,而不是 'large'。
搜索形式和简单形式
上面看到的是搜索形式:每个 WHEN 都有自己的布尔条件。当你要把一个表达式和几个常量比较时,还有一种更短的写法,即简单形式:
CASE 后面的表达式只计算一次,然后用 = 和每个 WHEN 的值进行比较。对单列做等值查找时,这种写法更简洁。
有一个坑:简单 CASE 使用 =,而在 SQL 中 NULL = NULL 不为真。如果 status 可能是 NULL,那么 'A'/'B'/'C' 这几个分支都匹配不上它,结果会落到 ELSE。要明确处理 NULL,请改用搜索形式,写 WHEN status IS NULL THEN ...。
在 ORDER BY 中使用 CASE
ORDER BY 接受任何表达式,所以 CASE 在这里也能正常使用。当你想要一种既不是字母顺序也不是数字顺序的自定义排序时,它很有用:
按字母顺序,'high' < 'low' < 'medium',这对按优先级处理任务毫无帮助。通过 CASE 把每个优先级映射成一个数字,就能得到你真正想要的顺序。末尾的 , id 让相同优先级的行保持稳定的顺序。
在 WHERE 中使用 CASE
你可以把 CASE 放进 WHERE,但大多数时候没必要,串联 AND/OR 会更清楚。它真正发挥作用的场景,是条件本身取决于另一个值的时候:
促销商品低于 20 就符合条件,普通商品要低于 30。阈值本身是有条件的。如果不用 CASE,你就得写 (on_sale = 1 AND price < 20) OR (on_sale = 0 AND price < 30),结果一样,但更啰嗦。
在聚合函数中使用 CASE
这才是 CASE 真正大显身手的地方。把它和 SUM 或 COUNT 结合起来,只扫描一遍表就能计算出一部分行的总计,相当于 SQL 版的“统计其中有多少个符合条件”:
CASE 对匹配的行返回 1,其他行返回 0,于是 SUM 就变成了条件计数。同样的技巧也适用于营收:在匹配的行上返回 total,其他地方都返回 0。扫描一遍表,就得到多个条件聚合。
IIF:两个分支时的简写
对于只有一个条件、两种结果的情况,SQLite 提供了 IIF(cond, when_true, when_false)。它纯粹是 CASE WHEN cond THEN when_true ELSE when_false END 的简写:
当逻辑只有两种结果、写成一行更好读时,用 IIF。当你有三个或更多分支、需要单独处理 NULL,或者需要多个 WHEN 子句依次匹配时,就改用 CASE。
值得了解的陷阱
有几件事常常让人吃亏:
- 忘了写
END。CASE开启一个代码块,END结束它。SQLite 报出的解析错误,位置往往离真正出错的地方很远。 - 没有
ELSE就返回NULL。 如果所有WHEN分支都不匹配,而你又省略了ELSE,结果就是NULL。有时这正是你想要的,但通常不是。 - 分支顺序很重要。 在搜索形式中,第一个匹配的
WHEN胜出。把WHEN total < 500放在WHEN total < 100之前,第二个分支就永远不会被执行到。 - 混用类型。 每个分支都可以返回不同的类型,SQLite 不会报错,但下游代码可能会出问题。尽量让所有分支返回兼容的类型(全是文本,或全是数值)。
- 简单
CASE和NULL。 前面提到过:简单形式使用=,永远匹配不到NULL。涉及 null 时请用搜索形式。
下一步:字符串函数
CASE 让你根据值进行分支判断;下一章开始讲转换值。字符串函数,比如 UPPER、LOWER、SUBSTR、REPLACE 和 LIKE 模式,负责清理和重新格式化文本列的日常工作。这就是接下来的内容。
常见问题
SQLite 中的 CASE 表达式是什么?
CASE 表达式就是 SQL 版的 if/else:它判断条件并返回一个值。它是一个表达式而不是语句,这意味着凡是可以放值的地方都能用它:SELECT、WHERE、ORDER BY、UPDATE,甚至聚合函数内部。每个分支的形式是 WHEN condition THEN value,末尾可以有一个可选的 ELSE。
SQLite 中简单 CASE 和搜索 CASE 有什么区别?
简单 CASE 把一个表达式和多个值进行比较:CASE status WHEN 'A' THEN ... WHEN 'B' THEN ... END。搜索 CASE 在每个分支里判断一个独立的布尔条件:CASE WHEN price > 100 THEN ... WHEN qty = 0 THEN ... END。搜索形式更灵活,可以自由组合不同的列、运算符和 NULL 检查。
SQLite 中什么时候该用 IIF 而不是 CASE?
IIF(cond, a, b) 是 CASE WHEN cond THEN a ELSE b END 的简写。只有两个分支、用 IIF 读起来更清楚时就用它。当你有三个或更多分支、需要依次匹配,或者要用 WHEN col IS NULL 明确处理 NULL 时,就改用 CASE。