广告位 · 页头(后台-模块管理-新建模块后替换此区域)

MySQL 如何使用 CASE WHEN 实现条件判断?

在 SQL 查询中,CASE WHEN 是一种非常实用的条件表达式,它允许我们把类似 if else 的分支逻辑直接写到 SQL 语句里。比如用户表里 status 字段存的是 0 和 1,但报表里想展示为“停用”和“启用”;再比如订单金额需要拆成不同区间进行统计,这些场景用 CASE WHEN 都能在一句 SQL 中完成,不需要把数据拉到应用层再循环处理。

MySQL 如何使用 CASE WHEN 实现条件判断?

一、CASE WHEN 的两种基础语法

MySQL 中的 CASE WHEN 有两种书写方式。第一种是简单 CASE,它的结构类似于很多编程语言里的 switch 语句,主要用来对单个字段进行等值判断。语法上以 CASE 开头,后面跟一个字段名,然后写多个 WHEN 值 THEN 结果的分支,最后用 END 结束。可以把它想象成“这个字段等于某个值时,就返回对应的结果”。

下面是一个简单 CASE 的示例,假设 users 表里 status 字段用 0 表示停用、1 表示启用,我们希望查询时直接显示中文状态:

SELECT name,
  CASE status
    WHEN 0 THEN '停用'
    WHEN 1 THEN '启用'
    ELSE '未知'
  END AS status_text
FROM users;

第二种是搜索 CASE,它比简单 CASE 更灵活,因为 WHEN 后面可以写任意条件表达式,比如大于、小于、LIKE、IN、逻辑组合等等。它不再局限于对某一个字段做等值比较。搜索 CASE 的语法是 CASE WHEN 条件 THEN 结果,多个 WHEN 可以分别判断不同字段或不同范围。

SELECT name, score,
  CASE
    WHEN score >= 90 THEN '优秀'
    WHEN score >= 80 THEN '良好'
    WHEN score >= 60 THEN '及格'
    ELSE '不及格'
  END AS level
FROM student_scores;

无论使用哪种语法,都有两点需要特别留意。第一,CASE WHEN 在匹配到第一个为真的 WHEN 分支后,会直接返回对应 THEN 的结果,不会再继续检查后面的 WHEN,所以条件顺序非常重要。第二,如果所有 WHEN 都没有匹配上,并且没有写 ELSE,那么整个 CASE 表达式会返回 NULL,这可能给后续统计或比较带来困扰,因此建议在大多数场景下补上 ELSE。

二、用 CASE WHEN 实现查询中的分类统计

CASE WHEN 最常见的用法之一就是在 SELECT 查询里做分类。比如订单表里有一个 amount 字段,我们想统计不同金额区间的订单数量。传统做法可能写多个查询用 UNION 拼接,或者写复杂子查询,但用 CASE WHEN 可以一次完成。把金额按区间转成一个新的分类字段,然后再用 GROUP BY 聚合,SQL 会很清晰。

SELECT
  CASE
    WHEN amount < 100 THEN '100以下'
    WHEN amount < 500 THEN '100-499'
    WHEN amount < 1000 THEN '500-999'
    ELSE '1000以上'
  END AS amount_level,
  COUNT(*) AS cnt
FROM orders
GROUP BY amount_level;

上面这段 SQL 中,CASE 表达式生成了一个别名 amount_level,MySQL 允许在 GROUP BY 里直接引用这个别名,这样语句更易读。需要注意的是,如果去掉 ELSE,金额大于等于 1000 的订单会落入 NULL 分组,实际业务中往往不希望出现这种不可控分组,所以养成写 ELSE 的习惯很重要。

除了普通分组统计,CASE WHEN 还经常配合聚合函数做条件聚合。例如我们想在一个结果行里同时看到已支付订单数和退款订单数,可以分别用 SUM 包裹 CASE WHEN,让满足条件的行返回 1,不满足的返回 0,再求和即可。

SELECT
  SUM(CASE WHEN status = 'paid' THEN 1 ELSE 0 END) AS paid_count,
  SUM(CASE WHEN status = 'refunded' THEN 1 ELSE 0 END) AS refunded_count
FROM orders;

条件聚合的好处是只需要扫描一次表,就能计算出多个不同维度下的统计结果。如果换成多个子查询或者多次执行 SELECT COUNT(*),不仅 SQL 更冗长,执行成本也可能更高。尤其在数据量较大的场景下,一次扫描加 CASE 判断通常是更好的选择。

三、在 UPDATE 和 ORDER BY 中的应用

CASE WHEN 不仅仅能用在 SELECT 里,在 UPDATE 语句中也很有价值。假设商品表要根据不同分类调整价格,A 类打 9 折、B 类打 8 折、其他不变。如果分开写多条 UPDATE,每一类都要扫描一次表,而用 CASE WHEN 可以一条语句完成所有行的条件更新。

UPDATE products
SET price = price * CASE
  WHEN category = 'A' THEN 0.9
  WHEN category = 'B' THEN 0.8
  ELSE 1.0
END;

这段 UPDATE 会对 products 表中的每一行计算一次 CASE 表达式,根据 category 字段决定乘以相应的系数。需要注意,如果某个分类没有被覆盖,而且没有写 ELSE,价格会被直接更新为 NULL,这是非常危险的操作。因此在使用 UPDATE 配合 CASE WHEN 时,ELSE 分支最好保留原值或者明确指定默认处理逻辑,避免数据被意外置空。

ORDER BY 里也经常需要按业务规则自定义排序顺序。例如工单表中有 open、processing、closed 三种状态,我们希望未处理的工单排在最前面,而不是按字母顺序排列。此时可以在 ORDER BY 后面使用 CASE WHEN,把每个状态映射成数字优先级。

SELECT * FROM tickets
ORDER BY
  CASE status
    WHEN 'open' THEN 1
    WHEN 'processing' THEN 2
    WHEN 'closed' THEN 3
    ELSE 4
  END,
  created_at DESC;

这个查询先按状态优先级升序排列,再按创建时间倒序排列,这样就能保证 open 状态的工单优先展示,同时同一状态下最新的记录排在上面。比起在应用层手动排序,SQL 里用 CASE WHEN 可以避免把大量数据加载到内存中,执行效率也更高。

四、与 IF 函数的区别以及性能注意事项

MySQL 还提供了一个 IF 函数,很多人会拿它和 CASE WHEN 做比较。IF(expr, true_value, false_value) 的优点是写起来更短,适合简单的二元判断。比如把 status 等于 1 转成“启用”,否则转成“停用”,一行就能搞定。但 IF 一旦出现多分支,就需要嵌套使用,可读性会明显下降。

SELECT IF(status = 1, '启用', IF(status = 0, '停用', '未知')) AS status_text
FROM users;

上面这种嵌套 IF 虽然能用,但分支一旦变多,括号和逗号很容易写错,后期维护也麻烦。相比之下,CASE WHEN 的扁平化结构更适合三个及以上的分支判断。另外,CASE WHEN 是 SQL 标准语法,在不同数据库之间迁移时会更容易,而 IF 函数在部分数据库里并不存在。因此如果只是简单的 if else,用 IF 没问题;但如果是多条件或多字段判断,更推荐使用 CASE WHEN。

在性能方面,CASE WHEN 一般不会带来明显的磁盘 IO 开销,它的计算发生在读取行数据之后,对 CPU 的消耗取决于表达式的复杂度。通常简单的等值或范围判断可以忽略不计。但要特别注意的是,不要在 WHERE 条件里对索引字段使用 CASE WHEN 进行包裹,否则 MySQL 可能无法利用索引,导致全表扫描。比如下面的写法虽然能得到结果,但效率通常较差:

SELECT * FROM orders
WHERE CASE WHEN status = 'paid' THEN 1 ELSE 0 END = 1;

这种写法等价于 status = 'paid',但 MySQL 很可能无法使用 status 字段上的索引。应该尽量保持 WHERE 条件简洁,直接写成 status = 'paid',把 CASE WHEN 集中放在 SELECT、ORDER BY 或 UPDATE 的 SET 等位置。另外,CASE WHEN 各分支返回的数据类型最好保持一致,避免 MySQL 进行隐式类型转换,这既有助于结果稳定,也能减少不必要的额外开销。

总的来说,CASE WHEN 是 MySQL 中一个非常灵活的条件表达式工具,掌握它的两种语法形式、典型使用场景以及性能注意点,能够显著提升 SQL 的表达能力和执行效率。当遇到需要按条件转换字段值、进行分类统计、动态排序或批量更新的需求时,优先考虑用 CASE WHEN 把逻辑下沉到 SQL 层,通常能让代码更简洁,也更贴近数据操作的本质。

广告位 · 文章底部(后台-模块管理替换此区域)