mysql从8.0版本开始支持窗口函数,它能在不改变结果集行数的情况下进行计算,使数据分析更高效;1. 窗口函数通过over()定义计算范围,支持partition by分组和order by排序;2. 常见函数包括rank()、dense_rank()、row_number()等排序函数,sum()、avg()等聚合函数,lag()、lead()等偏移函数,以及first_value()、last_value()、ntile()等;3. rank()并列时跳过后续排名,dense_rank()不跳过,row_number()生成唯一序号;4. 聚合函数作为窗口函数可实现累计计算,如累计工资;5. lag()和lead()用于获取前后行数据,常用于差值分析;6. first_value()取窗口首值,last_value()需配合rows between unbounded preceding and unbounded following才能取窗口末值;7. ntile(n)将数据按序分为n桶,用于分层分析;8. 性能优化建议包括为partition by和order by列建立索引、避免复杂表达式、合理设定窗口范围并避免过度使用窗口函数;掌握这些内容可有效提升复杂查询的编写效率与执行性能。

MySQL窗口函数,简单来说,就是在查询结果集上进行计算,但又不改变结果集的行数。它就像给你的数据加了一层“透视镜”,能让你看到更丰富的信息,而不用像GROUP BY那样改变数据的原始结构。
MySQL从8.0版本开始支持窗口函数,极大地增强了数据分析的能力。
MySQL窗口函数详解与实战案例
想象一下,你要计算每个部门的工资排名,或者找出每个月销售额最高的几天。如果用传统的SQL,你需要各种子查询和连接,代码又长又难懂。窗口函数就像一个“神奇的盒子”,它能在你的原始数据上进行计算,然后把结果“贴”回每一行数据上。这样,你就能在同一行看到原始数据和计算结果,分析起来方便多了。
窗口函数的核心在于“窗口”的概念,它定义了计算的范围。这个范围可以是整个结果集,也可以是按照某种条件划分的子集。
MySQL提供了丰富的窗口函数,大致可以分为以下几类:
RANK()
DENSE_RANK()
ROW_NUMBER()
SUM()
AVG()
MIN()
MAX()
COUNT()
PERCENT_RANK()
CUME_DIST()
LAG()
LEAD()
FIRST_VALUE()
LAST_VALUE()
NTH_VALUE()
NTILE()
这些函数的功能各不相同,但它们都遵循窗口函数的通用语法:
函数名(参数) OVER (PARTITION BY 列名 ORDER BY 列名)
PARTITION BY
ORDER BY
PARTITION BY
举个例子,假设我们有一个
employees
| name | department | salary |
|---|---|---|
| Alice | Sales | 5000 |
| Bob | Sales | 6000 |
| Carol | IT | 7000 |
| David | IT | 8000 |
| Eve | Sales | 5500 |
要计算每个部门的工资排名,可以使用以下SQL:
SELECT
name,
department,
salary,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS salary_rank
FROM
employees;结果如下:
| name | department | salary | salary_rank |
|---|---|---|---|
| Bob | Sales | 6000 | 1 |
| Eve | Sales | 5500 | 2 |
| Alice | Sales | 5000 | 3 |
| David | IT | 8000 | 1 |
| Carol | IT | 7000 | 2 |
可以看到,
RANK()
这三个排序函数都用于计算排名,但它们的行为略有不同。
RANK()
DENSE_RANK()
ROW_NUMBER()
继续上面的例子,如果我们在 Sales 部门添加一个工资为 6000 的员工 Frank:
| name | department | salary |
|---|---|---|
| Alice | Sales | 5000 |
| Bob | Sales | 6000 |
| Frank | Sales | 6000 |
| Carol | IT | 7000 |
| David | IT | 8000 |
| Eve | Sales | 5500 |
使用不同的排序函数:
SELECT
name,
department,
salary,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_rank,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dense_rank,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_number
FROM
employees;结果如下:
| name | department | salary | rank_rank | dense_rank | row_number |
|---|---|---|---|---|---|
| Bob | Sales | 6000 | 1 | 1 | 1 |
| Frank | Sales | 6000 | 1 | 1 | 2 |
| Eve | Sales | 5500 | 3 | 2 | 3 |
| Alice | Sales | 5000 | 4 | 3 | 4 |
| David | IT | 8000 | 1 | 1 | 1 |
| Carol | IT | 7000 | 2 | 2 | 2 |
可以看到,
RANK()
DENSE_RANK()
ROW_NUMBER()
SUM()
AVG()
MIN()
MAX()
COUNT()
动态WEB网站中的PHP和MySQL详细反映实际程序的需求,仔细地探讨外部数据的验证(例如信用卡卡号的格式)、用户登录以及如何使用模板建立网页的标准外观。动态WEB网站中的PHP和MySQL的内容不仅仅是这些。书中还提到如何串联JavaScript与PHP让用户操作时更快、更方便。还有正确处理用户输入错误的方法,让网站看起来更专业。另外还引入大量来自PEAR外挂函数库的强大功能,对常用的、强大的包
508
例如,要计算每个部门的累计工资:
SELECT
name,
department,
salary,
SUM(salary) OVER (PARTITION BY department ORDER BY salary) AS cumulative_salary
FROM
employees;结果如下:
| name | department | salary | cumulative_salary |
|---|---|---|---|
| Alice | Sales | 5000 | 5000 |
| Eve | Sales | 5500 | 10500 |
| Bob | Sales | 6000 | 16500 |
| Carol | IT | 7000 | 7000 |
| David | IT | 8000 | 15000 |
SUM(salary) OVER (PARTITION BY department ORDER BY salary)
LAG()
LEAD()
LAG(column, n, default_value)
LEAD(column, n, default_value)
例如,要计算每个员工的工资与前一个员工的工资差:
SELECT
name,
department,
salary,
salary - LAG(salary, 1, 0) OVER (PARTITION BY department ORDER BY salary) AS salary_difference
FROM
employees;结果如下:
| name | department | salary | salary_difference |
|---|---|---|---|
| Alice | Sales | 5000 | 5000 |
| Eve | Sales | 5500 | 500 |
| Bob | Sales | 6000 | 500 |
| Carol | IT | 7000 | 7000 |
| David | IT | 8000 | 1000 |
LAG(salary, 1, 0) OVER (PARTITION BY department ORDER BY salary)
LAG()
FIRST_VALUE()
LAST_VALUE()
FIRST_VALUE(column)
LAST_VALUE(column)
需要注意的是,
LAST_VALUE()
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
例如,要计算每个员工的工资与部门最高工资的差:
SELECT
name,
department,
salary,
MAX(salary) OVER (PARTITION BY department) - salary AS salary_difference
FROM
employees;或者使用
FIRST_VALUE()
LAST_VALUE()
SELECT
name,
department,
salary,
LAST_VALUE(salary) OVER (PARTITION BY department ORDER BY salary ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) - salary AS salary_difference
FROM
employees;这两个SQL语句的结果相同,都是计算每个员工的工资与部门最高工资的差。
NTILE(n)
例如,要将员工按照工资分成 3 个等级:
SELECT
name,
department,
salary,
NTILE(3) OVER (ORDER BY salary) AS salary_level
FROM
employees;结果如下:
| name | department | salary | salary_level |
|---|---|---|---|
| Alice | Sales | 5000 | 1 |
| Eve | Sales | 5500 | 1 |
| Bob | Sales | 6000 | 2 |
| Carol | IT | 7000 | 2 |
| David | IT | 8000 | 3 |
NTILE(3) OVER (ORDER BY salary)
窗口函数虽然强大,但使用不当也会影响性能。以下是一些性能优化建议:
PARTITION BY
ORDER BY
总之,窗口函数是MySQL中非常强大的数据分析工具。掌握窗口函数的使用,可以让你更轻松地完成各种复杂的数据分析任务。但同时也要注意性能优化,避免过度使用。
以上就是MySQL中常用的窗口函数有哪些 MySQL窗口函数详解与实战案例的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号