MySQL窗口函数实战:告别复杂子查询,轻松解决TopN排名难题
在日常开发中,处理排名、分组统计等场景时,你是否还在为复杂的子查询和临时表头疼?MySQL 8.0引入的窗口函数将彻底改变这一局面。本文将带你深入理解窗口函数的原理和应用,通过实际案例对比传统方案与窗口函数方案的差异,让你掌握这一高效的数据处理利器。
1. 窗口函数:数据处理的新范式
窗口函数(Window Function)是MySQL 8.0引入的一项重要特性,它能够在保留原始行数据的同时,对一组相关的行执行计算。与传统的GROUP BY聚合不同,窗口函数不会将多行合并为单行,而是为每一行返回一个计算结果,这使得我们能够在不改变结果集行数的情况下进行复杂分析。
窗口函数的三大核心优势:
- 保留原始数据:不像GROUP BY那样折叠行
- 灵活定义数据窗口:通过PARTITION BY和ORDER BY控制计算范围
- 多种计算模式:支持排名、聚合、前后行访问等多种操作
-- 基本语法结构
SELECT
column1,
column2,
window_function(column3) OVER (
[PARTITION BY partition_expression]
[ORDER BY order_expression [ASC|DESC]]
[frame_clause]
) AS alias_name
FROM table_name;
2. 排名函数三剑客:RANK、DENSE_RANK和ROW_NUMBER
在处理排名场景时,MySQL提供了三种常用的窗口函数,它们的行为有细微但重要的差异:
| 函数 | 相同值处理 | 排名连续性 | 典型应用场景 |
|---|---|---|---|
| ROW_NUMBER() | 始终分配唯一序号 | 连续 | 需要绝对唯一排名的场景 |
| RANK() | 相同值同排名,后续排名跳号 | 不连续 | 体育比赛排名,允许并列 |
| DENSE_RANK() | 相同值同排名,后续排名不跳号 | 连续 | 需要密集排名的场景 |
实际案例对比:假设我们有一个学生成绩表
CREATE TABLE student_scores (
student_id INT,
student_name VARCHAR(50),
subject VARCHAR(50),
score INT
);
INSERT INTO student_scores VALUES
(1, '张三', '数学', 90),
(2, '李四', '数学', 85),
(3, '王五', '数学', 90),
(4, '赵六', '数学', 78),
(5, '钱七', '数学', 85);
-- 三种排名函数对比
SELECT
student_name,
score,
ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num,
RANK() OVER (ORDER BY score DESC) AS rank_val,
DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank_val
FROM student_scores
WHERE subject = '数学';
执行结果将清晰展示三种函数的区别:
+-------------+-------+---------+----------+---------------+
| student_name | score | row_num | rank_val | dense_rank_val |
+-------------+-------+---------+----------+---------------+
| 张三 | 90 | 1 | 1 | 1 |
| 王五 | 90 | 2 | 1 | 1 |
| 李四 | 85 | 3 | 3 | 2 |
| 钱七 | 85 | 4 | 3 | 2 |
| 赵六 | 78 | 5 | 5 | 3 |
+-------------+-------+---------+----------+---------------+


847

被折叠的 条评论
为什么被折叠?



