条件表达式
条件表达式
想象你在餐厅点餐,服务员问你:"要辣的还是不辣的?微辣、中辣还是特辣?"——这就是条件判断:根据不同情况给出不同答案。SQL中的CASE WHEN也是同样的逻辑:根据不同条件返回不同的值,让你的查询结果更灵活、更有意义。
1. 核心概念
简单 CASE 语法
简单CASE将一个表达式与多个值进行比较,类似于编程语言中的switch语句。
CASE 表达式
WHEN 值1 THEN 结果1
WHEN 值2 THEN 结果2
...
ELSE 默认结果
END
-- 根据订单状态返回中文描述
SELECT order_id, status,
CASE status
WHEN 'completed' THEN '已完成'
WHEN 'shipped' THEN '已发货'
WHEN 'pending' THEN '待处理'
WHEN 'cancelled' THEN '已取消'
ELSE '未知状态'
END AS 状态描述
FROM orders;
搜索 CASE 语法
搜索CASE使用条件表达式,更灵活,可以处理复杂的判断逻辑。
CASE
WHEN 条件1 THEN 结果1
WHEN 条件2 THEN 结果2
...
ELSE 默认结果
END
-- 根据工资划分等级
SELECT first_name, last_name, salary,
CASE
WHEN salary >= 15000 THEN '高薪'
WHEN salary >= 10000 THEN '中等'
WHEN salary >= 7000 THEN '一般'
ELSE '待提升'
END AS 工资等级
FROM employees;
>、<、LIKE、IS NULL等任意条件。大多数场景推荐使用搜索CASE,更灵活。
CASE 在 SELECT 中的使用
在SELECT列列表中使用CASE,可以对每一行进行条件判断,生成新的计算列。
SELECT
CONCAT(first_name, last_name) AS 姓名,
salary AS 工资,
CASE
WHEN salary >= 12000 THEN '资深员工'
WHEN salary >= 8000 THEN '中级员工'
ELSE '初级员工'
END AS 职级
FROM employees;
CASE 在 ORDER BY 中的使用
用CASE自定义排序规则,实现"按指定顺序排列"。
-- 按状态自定义排序:待处理 > 已发货 > 已完成 > 已取消
SELECT order_id, status, total_amount
FROM orders
ORDER BY
CASE status
WHEN 'pending' THEN 1
WHEN 'shipped' THEN 2
WHEN 'completed' THEN 3
WHEN 'cancelled' THEN 4
END;
CASE 在 GROUP BY 中的使用
配合聚合函数实现条件统计(行转列),是数据分析中的常用技巧。
-- 统计每种订单状态的数量
SELECT
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) AS 已完成,
SUM(CASE WHEN status = 'shipped' THEN 1 ELSE 0 END) AS 已发货,
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) AS 待处理,
SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) AS 已取消
FROM orders;
CASE 在 UPDATE 中的使用
在UPDATE语句中用CASE实现批量条件更新,一次SQL完成多种更新逻辑。
-- 根据绩效调整工资
UPDATE employees
SET salary = CASE
WHEN salary < 8000 THEN salary * 1.15
WHEN salary < 12000 THEN salary * 1.10
ELSE salary * 1.05
END;
IF / IFNULL / COALESCE
MySQL提供了比CASE更简洁的条件函数:
| 函数 | 语法 | 用途 |
|---|---|---|
IF |
IF(条件, 真值, 假值) |
简单二选一 |
IFNULL |
IFNULL(表达式, 替代值) |
NULL时返回替代值 |
COALESCE |
COALESCE(值1, 值2, ...) |
返回第一个非NULL值 |
-- IF:简单二选一
SELECT IF(salary > 10000, '高薪', '普通') AS 级别 FROM employees;
-- IFNULL:处理NULL
SELECT IFNULL(department_id, 0) AS 部门ID FROM employees;
-- COALESCE:返回第一个非NULL
SELECT COALESCE(commission, bonus, 0) AS 奖金 FROM employees;
COALESCE是SQL标准函数,支持多个参数;IFNULL是MySQL特有函数,只支持两个参数。推荐使用COALESCE,兼容性更好。
2. 基本语法
CASE WHEN 完整语法
-- 简单CASE
CASE 表达式
WHEN 值1 THEN 结果1
WHEN 值2 THEN 结果2
[ELSE 默认结果]
END
-- 搜索CASE
CASE
WHEN 条件1 THEN 结果1
WHEN 条件2 THEN 结果2
[ELSE 默认结果]
END
条件函数语法
IF(条件, 真值, 假值)
IFNULL(表达式, 替代值)
COALESCE(值1, 值2, ..., 值N)
COALESCE可以替代IFNULL,且支持多个备选值,推荐优先使用。
示例:为订单添加状态标签和优先级(难度⭐)
SELECT
order_id AS 订单号,
CONCAT(e.first_name, e.last_name) AS 负责人,
o.total_amount AS 金额,
CASE status
WHEN 'completed' THEN '✅ 已完成'
WHEN 'shipped' THEN '🚚 已发货'
WHEN 'pending' THEN '⏳ 待处理'
WHEN 'cancelled' THEN '❌ 已取消'
ELSE '❓ 未知'
END AS 状态,
CASE
WHEN total_amount >= 3000 THEN '高'
WHEN total_amount >= 1000 THEN '中'
ELSE '低'
END AS 优先级
FROM orders o
LEFT JOIN employees e ON o.employee_id = e.employee_id
ORDER BY
CASE
WHEN total_amount >= 3000 THEN 1
WHEN total_amount >= 1000 THEN 2
ELSE 3
END;
输出:
订单号 | 负责人 | 金额 | 状态 | 优先级
------+--------+-----------+---------+------
1005 | 赵敏 | 4100.00 | ✅ 已完成 | 高
1003 | 赵敏 | 3200.00 | 🚚 已发货 | 高
1006 | 王强 | 2800.00 | ❌ 已取消 | 中
1001 | 王强 | 2500.00 | ✅ 已完成 | 中
1002 | 王强 | 1800.00 | ✅ 已完成 | 中
1004 | 张伟 | 950.00 | ⏳ 待处理 | 低
查询思路:
- 第一个CASE将英文状态转为中文标签
- 第二个CASE按金额划分优先级
- ORDER BY中的CASE实现按优先级排序
示例:按部门统计各工资等级的人数(难度⭐⭐)
SELECT
d.department_name AS 部门,
COUNT(*) AS 总人数,
SUM(CASE WHEN e.salary >= 12000 THEN 1 ELSE 0 END) AS 高薪,
SUM(CASE WHEN e.salary >= 8000 AND e.salary < 12000 THEN 1 ELSE 0 END) AS 中等,
SUM(CASE WHEN e.salary < 8000 THEN 1 ELSE 0 END) AS 一般,
AVG(e.salary) AS 平均工资
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id
GROUP BY d.department_name
ORDER BY 平均工资 DESC;
输出:
部门 | 总人数 | 高薪 | 中等 | 一般 | 平均工资
------+--------+------+------+------+---------
技术部 | 2 | 1 | 1 | 0 | 10750.00
销售部 | 2 | 1 | 1 | 0 | 9500.00
市场部 | 1 | 0 | 0 | 1 | 7500.00
NULL | 1 | 0 | 1 | 0 | 9000.00
查询思路:
- GROUP BY按部门分组
- 每个SUM(CASE ...)统计满足条件的人数,实现行转列
- 同时计算平均工资作为参考
3. 常见应用场景
场景一:动态标签 — 根据多维度条件给员工打标签
SELECT
CONCAT(e.first_name, e.last_name) AS 姓名,
d.department_name AS 部门,
e.salary AS 工资,
CASE
WHEN e.salary >= 12000 AND d.department_name = '技术部' THEN '核心技术骨干'
WHEN e.salary >= 12000 THEN '高级员工'
WHEN e.salary >= 8000 AND e.hire_date < '2023-06-01' THEN '资深中级员工'
WHEN e.salary >= 8000 THEN '中级员工'
ELSE '初级员工'
END AS 员工标签
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id
ORDER BY e.salary DESC;
输出:
姓名 | 部门 | 工资 | 员工标签
----+--------+-----------+----------
张伟 | 技术部 | 12000.00 | 核心技术骨干
赵敏 | 销售部 | 11000.00 | 高级员工
李娜 | 技术部 | 9500.00 | 资深中级员工
陈静 | NULL | 9000.00 | 中级员工
王强 | 销售部 | 8000.00 | 资深中级员工
刘洋 | 市场部 | 7500.00 | 初级员工
场景二:UPDATE + CASE 批量条件更新
-- 根据入职年限和部门调整工资
UPDATE employees
SET salary = CASE
WHEN department_id = 1 AND hire_date < '2023-01-01' THEN salary * 1.15
WHEN department_id = 1 THEN salary * 1.10
WHEN department_id = 2 THEN salary * 1.08
WHEN department_id IS NULL THEN salary * 1.05
ELSE salary * 1.03
END;
❓ 常见问题
Q:CASE WHEN和IF有什么区别?该用哪个? A:
IF只能处理二选一(真/假),适合简单场景;CASE WHEN可以处理多个条件分支,适合复杂逻辑。MySQL中IF更简洁,但CASE WHEN是SQL标准,跨数据库兼容性更好。建议复杂条件用CASE,简单判断用IF或COALESCE。
Q:CASE表达式可以用在WHERE子句中吗? A: 可以,但不推荐。通常应该把条件直接写在WHERE中,而不是用CASE包装。CASE更适合在SELECT中生成新列、在ORDER BY中自定义排序、在GROUP BY中做条件聚合。
Q:CASE WHEN的执行顺序是怎样的? A: CASE按WHEN子句的书写顺序依次判断,一旦某个WHEN条件为真,就返回对应的THEN值,后续WHEN不再判断。所以应该把最常见或最优先的条件放在前面。
Q:COALESCE和IFNULL哪个更好? A:
COALESCE是SQL标准函数,支持多个参数(如COALESCE(a, b, c, 0)),跨数据库通用;IFNULL是MySQL特有函数,只支持两个参数。推荐使用COALESCE,兼容性和灵活性都更好。
📖 小节
CASE WHEN是SQL的条件表达式,可以出现在SELECT、WHERE、ORDER BY、GROUP BY等任何位置- 简单CASE:等值比较,适合"一个字段匹配多个值"的场景
- 搜索CASE:任意条件,适合复杂判断,推荐优先使用
- CASE在GROUP BY中:配合SUM/COUNT实现条件统计(行转列),是数据分析的核心技巧
- CASE在UPDATE中:一次UPDATE完成多种更新逻辑
- IF/IFNULL/COALESCE:更简洁的条件函数,COALESCE兼容性最好
📝 作业
作业1(⭐):查询所有订单,添加一个"金额等级"列:金额>=3000为"大单",1000-2999为"中单",<1000为"小单"。按金额等级排序。
作业2(⭐⭐):按员工统计订单情况,使用CASE WHEN配合聚合函数,生成如下报表:员工姓名、总订单数、已完成订单数、待处理订单数、总销售额。
作业3(⭐⭐):使用UPDATE + CASE,将"销售部"员工工资提升10%,"技术部"提升8%,其他部门提升5%。
下一课
👉 17-views-indexes - 视图与索引:学习视图(虚拟表)的创建和使用,以及索引的概念和优化策略!



