🎯 本月只剩几天支持 SQLTest.online,帮助我们让 SQL 练习对每个人都免费。 今天捐赠 →
SQL 代码已复制到剪贴板

SQL CASE WHEN:查询中的条件逻辑

第 3.5 课 · 阅读时间:约 7 分钟 · 练习题 ↓

SQL CASE 表达式为查询添加“如果-那么-否则”逻辑:它按顺序检查条件,并返回第一个为真的条件所对应的值。在本课中,你将学习 CASE 的两种形式、如何在 SELECT 中创建分类和标签、如何按自定义优先级排序,以及如何在 WHERE 中使用 CASE。

前面课程中的函数对每一行都做同样的转换。但规则常常取决于数据本身:低于 2 美元的付款算“小额”,高于 6 美元算“大额”;没有归还日期的租赁算“未归还”。CASE 让你可以直接在 SQL 中写出这些规则,而不必放到应用程序代码里处理。

SQL CASE WHEN:条件从上到下依次检查,第一个为真的条件返回其值,ELSE 作为默认值,CASE 可用于标签和自定义排序

CASE 语法

CASE 有两种形式。

搜索 CASE

每个 WHEN 都包含自己的条件。这是更灵活、也更常用的形式:

CASE
    WHEN condition1 THEN result1
    WHEN condition2 THEN result2
    ELSE default_result
END

简单 CASE

将一个表达式与一组值进行比较:

CASE expression
    WHEN value1 THEN result1
    WHEN value2 THEN result2
    ELSE default_result
END

CASE 的求值方式

  • 条件从上到下依次检查。
  • 返回第一个为真的条件的结果;其余条件不再检查。
  • 如果没有条件为真,则返回 ELSE 的值。
  • 如果没有 ELSE,结果为 NULL。

CASE 是一个表达式,而不是独立的语句:它返回一个值,可以用在任何允许使用值的地方,例如 SELECT、WHERE 或 ORDER BY。


SELECT 中的 CASE:分类和标签

付款级别

SELECT payment_id,
       amount,
       CASE
           WHEN amount < 2 THEN 'Low'
           WHEN amount < 6 THEN 'Medium'
           ELSE 'High'
       END AS payment_level
FROM payment
LIMIT 10;

结果:十笔付款,每笔都有一个级别:低于 2 美元为“Low”,2 美元到 6 美元以下为“Medium”,6 美元及以上为“High”。

条件的顺序很重要。1 美元的付款也满足 amount < 6,但它得到的是“Low”,因为第一个匹配的分支胜出。正因如此,第二个条件不需要写下限。

可读的状态

SELECT rental_id,
       rental_date,
       CASE
           WHEN return_date IS NULL THEN 'Not returned'
           ELSE 'Returned'
       END AS rental_status
FROM rental
ORDER BY rental_date DESC
LIMIT 10;

结果:最近的租赁记录,用文本状态代替空的或已填写的归还日期。

用简单 CASE 处理代码

当列中存放的是代码时,简单形式很方便:

SELECT title,
       rating,
       CASE rating
           WHEN 'G' THEN 'General audiences'
           WHEN 'PG' THEN 'Parental guidance'
           WHEN 'PG-13' THEN 'Parents strongly cautioned'
           WHEN 'R' THEN 'Restricted'
           ELSE 'Adults only'
       END AS rating_description
FROM film
LIMIT 10;

结果:电影及其分级的可读说明。


ORDER BY 中的 CASE:自定义排序

分级代码的字母顺序(G、NC-17、PG、PG-13、R)与它们的含义并不一致。CASE 可以把每个代码转换为一个优先级数字:

SELECT title, rating
FROM film
ORDER BY CASE rating
             WHEN 'G' THEN 1
             WHEN 'PG' THEN 2
             WHEN 'PG-13' THEN 3
             WHEN 'R' THEN 4
             ELSE 5
         END,
         title;

结果:电影从最宽松的分级排到最严格的分级;同一分级内按片名排序。

同样的技巧可以把重要的行放到最前面:

SELECT rental_id, rental_date, return_date
FROM rental
ORDER BY CASE WHEN return_date IS NULL THEN 0 ELSE 1 END,
         rental_date DESC
LIMIT 20;

结果:先显示未归还的租赁,然后是其余租赁;每组内最新的排在前面。


WHERE 中的 CASE

CASE 可以为条件返回一个值,例如取决于另一列的阈值:

SELECT payment_id, staff_id, amount
FROM payment
WHERE amount >= CASE
                    WHEN staff_id = 1 THEN 5
                    ELSE 3
                END
LIMIT 10;

结果:员工 1 经手的金额不低于 5 美元的付款,以及其他员工经手的金额不低于 3 美元的付款。

大多数这类过滤条件也可以用 AND 和 OR 来写:WHERE (staff_id = 1 AND amount >= 5) OR (staff_id <> 1 AND amount >= 3)。选择更易读的写法:两个分支时通常用 OR,分支很多时用 CASE。


实用建议

  • 始终写上 ELSE。没有它,意料之外的值会变成 NULL,这样的行很容易被忽略。
  • 返回同一种数据类型。在不同分支中混用文本和数字会导致隐式转换和意外结果。
  • 按从具体到一般的顺序排列条件。第一个为真的分支胜出。
  • 在第 4.4 课中,你将在聚合函数内部使用 CASE,用一个查询按类别统计行数。

要点:

  • CASE 返回第一个为真的 WHEN 条件的结果;如果都不为真,则返回 ELSE。
  • 搜索 CASE 可以检查任意条件;简单 CASE 把一个表达式与若干值比较。
  • 没有 ELSE 时,结果为 NULL。
  • 在 SELECT 中,CASE 用于创建分类和可读的标签。
  • 在 ORDER BY 中,它可以设置自定义排序;在 WHERE 中,它可以让过滤条件依赖于其他列。

常见问题

简单 CASE 和搜索 CASE 有什么区别?

简单 CASE 把一个表达式与一组值比较:CASE rating WHEN 'G' THEN ...。搜索 CASE 在每个分支中检查独立的条件:CASE WHEN amount < 2 THEN ...。搜索 CASE 能做简单形式能做的一切,还能处理范围、NULL 检查以及涉及多列的条件。

如果没有条件为真且没有 ELSE,CASE 会返回什么?

NULL。为避免意外,请始终添加一个带有明确默认值的 ELSE 分支。

SQL 中有 IF 函数吗?

标准做法是使用 CASE。MySQL 和 MariaDB 还有 IF(condition, value_if_true, value_if_false),SQL Server 有 IIF(),但它们不可移植。

尝试解决以下任务,以巩固您在本课中学到的内容。

  1. 每日航班数量
  2. 调整租赁成本