MySQL 中 case when的五种使用位置
作者:AlbenXie
CASE WHEN 属于条件表达式,本质是返回一个值,几乎可以放在 SQL 绝大部分区域,下面按使用场景逐一说明,附带可运行案例。
一、放在 SELECT 子句(最常用)
作用:查询结果里新增自定义条件列、字段值转换、分类打标签
语法格式
CASE
WHEN 条件1 THEN 结果1
WHEN 条件2 THEN 结果2
ELSE 默认值
END 别名
简写(等值判断专用):
CASE 字段
WHEN 值1 THEN 结果1
ELSE ...
END
示例:员工薪资分级
SELECT
emp_name,
salary,
CASE
WHEN salary >= 15000 THEN '高薪'
WHEN salary >= 8000 THEN '中产'
ELSE '基础薪资'
END AS salary_level
FROM employees;
二、放在 WHERE 条件中
作用:动态筛选数据,根据条件灵活拼接筛选规则 示例:部门 10 只查高薪员工,其他部门查全部
SELECT emp_name,department_id,salary
FROM employees
WHERE
CASE department_id
WHEN 10 THEN salary >= 15000
ELSE 1=1 -- 恒成立,不做限制
END;
等价普通写法:
WHERE (department_id=10 AND salary>=15000) OR department_id<>10
三、放在 GROUP BY 分组里
作用:按照条件分类分组,不再依据原始字段分组 需求:把薪资划分档次,统计每个档次人数
SELECT
CASE
WHEN salary >= 15000 THEN '高薪'
WHEN salary >= 8000 THEN '中产'
ELSE '基础薪资'
END AS level,
COUNT(*) AS total
FROM employees
GROUP BY
CASE
WHEN salary >= 15000 THEN '高薪'
WHEN salary >= 8000 THEN '中产'
ELSE '基础薪资'
END;
小技巧:MySQL 支持 GROUP BY 别名
GROUP BY level;
四、放在 ORDER BY 排序中
作用:自定义排序优先级,不按照字段原生数值排序 场景:优先把经理排最前面,普通员工次之
SELECT emp_name,job
FROM employees
ORDER BY
CASE job
WHEN 'manager' THEN 1
WHEN 'leader' THEN 2
ELSE 3
END ASC;
五、放在 HAVING 分组后过滤
作用:对聚合之后的结果做条件筛选 示例:统计各部门人数,只保留人数较多的部门
SELECT
department_id,
COUNT(*) cnt
FROM employees
GROUP BY department_id
HAVING
CASE
WHEN department_id IN (10,20) THEN cnt >= 3
ELSE cnt >= 1
END;
六、放在 UPDATE 更新语句内
作用:批量条件更新数据 需求:高薪涨薪 2000,中产涨 1000
UPDATE employees
SET salary = salary +
CASE
WHEN salary >= 15000 THEN 2000
WHEN salary >= 8000 THEN 1000
ELSE 500
END;
七、CASE WHEN 不能使用的地方
- 不能放在 FROM 里充当表(它是表达式,不是数据表)
- 不能用作表名、字段名(无法动态替换标识符)
- 不能替代 JOIN 关联条件
易混小知识点
- CASE 结尾必须加
END,缺一不可; - ELSE 可以省略,不满足所有条件时默认返回 NULL;
- 等值判断用简写 CASE,区间、多条件判断用完整 CASE WHEN。
按照标准 SQL 逻辑执行顺序:GROUP BY 早于 SELECT,理论上绝对不能使用别名; 但 MySQL 官方做了非标准扩展,语法上可以运行,底层做了特殊解析替换,并非真的读取到了 SELECT 之后才生成的别名CSDN博...。
一、先牢记标准 SQL 逻辑执行顺序(全世界通用)
FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT(生成别名)→ DISTINCT → ORDER BY → LIMIT
关键点: GROUP BY 阶段执行时,SELECT 还没运行,别名根本不存在 Oracle、PostgreSQL、SQL Server 严格遵守标准,GROUP BY 写别名直接报错。
二、MySQL 为什么可以写 GROUP BY 别名?底层原理
MySQL 解析 SQL 时做了预扫描替换:
- 解析器先通读整条 SQL,识别出 SELECT 里的别名与对应的原始表达式
- 遇到
GROUP BY level时,自动把别名 还原回 CASE WHEN 完整表达式 再执行分组
-- 你写的
SELECT
CASE WHEN salary>=15000 THEN '高薪' ELSE '普通' END AS level,
COUNT(*) num
FROM employees
GROUP BY level;
-- MySQL内部等价翻译成下面这条再执行
SELECT
CASE WHEN salary>=15000 THEN '高薪' ELSE '普通' END AS level,
COUNT(*) num
FROM employees
GROUP BY CASE WHEN salary>=15000 THEN '高薪' ELSE '普通' END;
本质没有违背执行顺序,只是语法糖简化书写CSDN博...。
三、各个位置别名使用边界对照表
| 位置 | 标准 SQL | MySQL 实际表现 | 原因 |
|---|---|---|---|
| WHERE | ❌ 禁止 | ❌ 依旧不能用 | 太早,无预解析替换 |
| GROUP BY | ❌ 禁止 | ✅ 支持(扩展) | 预解析替换表达式 |
| HAVING | ❌ 禁止 | ✅ 支持(扩展) | 同样预解析替换 |
| ORDER BY | ✅ 允许 | ✅ 允许 | 在 SELECT 之后执行,天然能读到别名 |
举例区分
-- 错误:WHERE 永远不能用别名 SELECT salary AS s FROM employees WHERE s>5000; -- MySQL合法:GROUP BY、HAVING可用别名 SELECT salary AS s,COUNT(*) cnt FROM employees GROUP BY s HAVING cnt>2;
四、ONLY_FULL_GROUP_BY 开启后还能用吗?
完全可以。 MySQL8.0/5.7 默认开启该严格模式,GROUP BY 引用别名依然生效,校验机制会识别别名和分组表达式一一对应,不会报错MySQL。
五、生产环境建议
- 追求跨数据库兼容、严谨性:不推荐 GROUP BY 写别名 换成原始表达式,迁移 Oracle、PG 不会出错;
- 只跑 MySQL、追求简洁:可以使用;
- WHERE 任何场景都不要尝试别名。
到此这篇关于MySQL 中 case when的五种使用位置的文章就介绍到这了,更多相关MySQL case when位置内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
