Menu

SQL CASE WHEN 用法(SQLite):THEN、ELSE 与 IIF

CASE 在 SQLite 中如何工作:简单形式和搜索形式,在 SELECT、ORDER BY 和 WHERE 中的用法,以及什么时候该改用 IIF。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

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。

Coddy 编程语言插图

和 Coddy 一起学编程

开始