404 Not Found

404 Not Found


nginx

条件表达式

条件表达式

想象你在餐厅点餐,服务员问你:"要辣的还是不辣的?微辣、中辣还是特辣?"——这就是条件判断:根据不同情况给出不同答案。SQL中的CASE WHEN也是同样的逻辑:根据不同条件返回不同的值,让你的查询结果更灵活、更有意义。


1. 核心概念

简单 CASE 语法

简单CASE将一个表达式与多个值进行比较,类似于编程语言中的switch语句。

SQL
CASE 表达式
    WHEN 值1 THEN 结果1
    WHEN 值2 THEN 结果2
    ...
    ELSE 默认结果
END
SQL
-- 根据订单状态返回中文描述
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使用条件表达式,更灵活,可以处理复杂的判断逻辑。

SQL
CASE
    WHEN 条件1 THEN 结果1
    WHEN 条件2 THEN 结果2
    ...
    ELSE 默认结果
END
SQL
-- 根据工资划分等级
SELECT first_name, last_name, salary,
    CASE
        WHEN salary >= 15000 THEN '高薪'
        WHEN salary >= 10000 THEN '中等'
        WHEN salary >= 7000  THEN '一般'
        ELSE '待提升'
    END AS 工资等级
FROM employees;
💡 简单CASE vs 搜索CASE:简单CASE只能做等值比较;搜索CASE可以使用><LIKEIS NULL等任意条件。大多数场景推荐使用搜索CASE,更灵活。

CASE 在 SELECT 中的使用

在SELECT列列表中使用CASE,可以对每一行进行条件判断,生成新的计算列。

SQL
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自定义排序规则,实现"按指定顺序排列"。

SQL
-- 按状态自定义排序:待处理 > 已发货 > 已完成 > 已取消
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 中的使用

配合聚合函数实现条件统计(行转列),是数据分析中的常用技巧。

SQL
-- 统计每种订单状态的数量
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完成多种更新逻辑。

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值
SQL
-- 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 vs IFNULLCOALESCE是SQL标准函数,支持多个参数;IFNULL是MySQL特有函数,只支持两个参数。推荐使用COALESCE,兼容性更好。


2. 基本语法

CASE WHEN 完整语法

SQL
-- 简单CASE
CASE 表达式
    WHEN 值1 THEN 结果1
    WHEN 值2 THEN 结果2
    [ELSE 默认结果]
END

-- 搜索CASE
CASE
    WHEN 条件1 THEN 结果1
    WHEN 条件2 THEN 结果2
    [ELSE 默认结果]
END
💡 提示:CASE表达式会返回一个值,可以出现在任何能使用表达式的地方(SELECT、WHERE、ORDER BY、GROUP BY等)。WHEN子句按顺序匹配,一旦找到匹配就返回结果,后续WHEN不再判断。

💡 提示:如果省略ELSE且没有匹配项,CASE返回NULL。建议始终写ELSE处理意外情况。

条件函数语法

SQL
IF(条件, 真值, 假值)
IFNULL(表达式, 替代值)
COALESCE(值1, 值2, ..., 值N)
💡 提示COALESCE可以替代IFNULL,且支持多个备选值,推荐优先使用。


示例:为订单添加状态标签和优先级(难度⭐)

SQL
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;
▶ 试一试

输出:

TEXT
订单号 | 负责人 | 金额      | 状态     | 优先级
------+--------+-----------+---------+------
 1005 | 赵敏   | 4100.00   | ✅ 已完成 | 高
 1003 | 赵敏   | 3200.00   | 🚚 已发货 | 高
 1006 | 王强   | 2800.00   | ❌ 已取消 | 中
 1001 | 王强   | 2500.00   | ✅ 已完成 | 中
 1002 | 王强   | 1800.00   | ✅ 已完成 | 中
 1004 | 张伟   |  950.00   | ⏳ 待处理 | 低

查询思路:

  1. 第一个CASE将英文状态转为中文标签
  2. 第二个CASE按金额划分优先级
  3. ORDER BY中的CASE实现按优先级排序

示例:按部门统计各工资等级的人数(难度⭐⭐)

SQL
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;
▶ 试一试

输出:

TEXT
部门   | 总人数 | 高薪 | 中等 | 一般 | 平均工资
------+--------+------+------+------+---------
技术部 |      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

查询思路:

  1. GROUP BY按部门分组
  2. 每个SUM(CASE ...)统计满足条件的人数,实现行转列
  3. 同时计算平均工资作为参考

3. 常见应用场景

场景一:动态标签 — 根据多维度条件给员工打标签

SQL
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;

输出:

TEXT
姓名 | 部门   | 工资      | 员工标签
----+--------+-----------+----------
张伟 | 技术部 | 12000.00  | 核心技术骨干
赵敏 | 销售部 | 11000.00  | 高级员工
李娜 | 技术部 |  9500.00  | 资深中级员工
陈静 | NULL   |  9000.00  | 中级员工
王强 | 销售部 |  8000.00  | 资深中级员工
刘洋 | 市场部 |  7500.00  | 初级员工
💡 思路:搜索CASE的WHEN按顺序匹配,一旦命中就返回,所以条件的顺序很重要——更具体的条件应放在前面。

场景二:UPDATE + CASE 批量条件更新

SQL
-- 根据入职年限和部门调整工资
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;
💡 思路:一次UPDATE完成多种更新逻辑,避免写多条UPDATE语句。CASE按顺序匹配,所以"技术部且入职早"的条件放在"技术部"前面。


❓ 常见问题

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,兼容性和灵活性都更好。


📖 小节


📝 作业

作业1(⭐):查询所有订单,添加一个"金额等级"列:金额>=3000为"大单",1000-2999为"中单",<1000为"小单"。按金额等级排序。

作业2(⭐⭐):按员工统计订单情况,使用CASE WHEN配合聚合函数,生成如下报表:员工姓名、总订单数、已完成订单数、待处理订单数、总销售额。

作业3(⭐⭐):使用UPDATE + CASE,将"销售部"员工工资提升10%,"技术部"提升8%,其他部门提升5%。


下一课

👉 17-views-indexes - 视图与索引:学习视图(虚拟表)的创建和使用,以及索引的概念和优化策略!

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏