同学,窗口函数和 CTE 是 MySQL 进阶的分水岭,也是面试官判断你 "有没有系统学过" 的题。这篇是加分项,可得拿下。
一、CASE WHEN:两种写法都要会
-- 写法一:简单 CASE(等值判断)
SELECT name,
CASE gender WHEN '男' THEN 'M' ELSE 'F' END AS g
FROM student;
-- 写法二:搜索 CASE(条件判断,更灵活)
SELECT name, age,
CASE
WHEN age < 18 THEN '未成年'
WHEN age < 60 THEN '成年'
ELSE '老年'
END AS stage
FROM student;
CASE WHEN 还能用在 WHERE (动态过滤)、ORDER BY (自定义排序)、GROUP BY (自定义分组)。 三个注意点: ① 必须写
END;② 按顺序返回第一个匹配的;③ 建议写ELSE兜底。
二、CTE(WITH,MySQL 8.0 新功能)
-- 场景:查高于部门平均工资的员工
WITH dept_avg AS (
SELECT dept_id, AVG(salary) AS avg_sal
FROM emp
GROUP BY dept_id
)
SELECT e.*
FROM emp e
JOIN dept_avg d ON e.dept_id = d.dept_id
WHERE e.salary > d.avg_sal;
作用:把复杂查询拆成可读的临时结果集,让 SQL 模块化、可复用,比嵌套子查询清爽得多。
三、窗口函数(核心区别:不减少行数)
窗口函数和聚合函数最大的区别:
- 聚合函数 把多行压成一行(
AVG返回一个值)。 - 窗口函数 不压缩行数,每一行都返回结果,适合算排名、移动平均这种。
1)排序类(最常考):
SELECT name, dept_id, salary,
ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rn, -- 严格连续 1,2,3
RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rk, -- 有并列就跳号 1,1,3
DENSE_RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS drk -- 有并列不跳号 1,1,2
FROM emp;
区别记住:
ROW_NUMBER永远连续;RANK并列跳号;DENSE_RANK并列不跳号。面试常让三选一。
2)聚合类:
-- 累计求和(跑了多少天卖了多少)
SELECT date, amount,
SUM(amount) OVER (ORDER BY date) AS running_total
FROM sales;
3)偏移类(LAG / LEAD):
-- 看"今天和昨天的差距"
SELECT date, amount,
LAG(amount) OVER (ORDER BY date) AS prev_amount, -- 上一条
LEAD(amount) OVER (ORDER BY date) AS next_amount -- 下一条
FROM sales;
4)首尾类(FIRST_VALUE / LAST_VALUE / NTH_VALUE):
-- 每个部门最高薪资
SELECT name, dept_id, salary,
FIRST_VALUE(salary) OVER (PARTITION BY dept_id ORDER BY salary DESC) AS highest_sal
FROM emp;
老哥一句话:窗口函数
OVER()里的PARTITION BY相当于 "分组",ORDER BY相当于 "组内排序",先想清楚你要按什么分组、按什么排序,再选函数,就错不了。MySQL 8.0 才支持窗口函数。