

"为什么同样的统计需求,别人用3行SQL就能实现,我却要写30行嵌套查询?" 这是许多SQL开发者都曾有过的困惑。在后端程序员日常工作中,排名统计、累计计算、分组对比等需求就像顽固的"钉子户",直到我们遇见MySQL 8.0带来的窗口函数——这个数据库领域的"瑞士军刀",彻底改变了我们处理复杂统计的方式。
今天小编通过三个真实业务场景,手把手教大家用ROW_NUMBER()和SUM() OVER()两大神器,轻松攻克那些曾让你头疼的数据库统计难题!
窗口函数(Window Function)是一种特殊类型的SQL函数,它能够在保持原有行数据完整性的同时,对数据集的特定子集(称为"窗口")进行计算。就像给数据安装了一面"透视镜",既能看到整体数据全貌,又能聚焦局部细节。
<!--br {mso-data-placement:same-cell;}--> td {white-space:nowrap;border:0.5pt solid #dee0e3;font-size:10pt;font-style:normal;font-weight:normal;vertical-align:middle;word-break:normal;word-wrap:normal;}
特征 | 普通聚合函数 | 窗口函数 |
|---|---|---|
数据维度 | 折叠为单行 | 保留原始行数据 |
计算范围 | 全局或GROUP BY分组 | 可定义滑动窗口范围 |
典型函数 | SUM/AVG/COUNT等 | ROW_NUMBER/RANK/LEAD等 |
使用场景 | 汇总统计 | 复杂分析(排名/移动平均等) |
函数名() OVER (
[PARTITION BY 分区字段]
[ORDER BY 排序字段]
[ROWS/RANGE 窗口范围]
)<!--br {mso-data-placement:same-cell;}--> td {white-space:nowrap;border:0.5pt solid #dee0e3;font-size:10pt;font-style:normal;font-weight:normal;vertical-align:middle;word-break:normal;word-wrap:normal;}
函数类型 | 代表函数 | 典型应用 |
|---|---|---|
排名函数 | ROW_NUMBER/RANK/DENSE_RANK | 销售排名/成绩排名 |
聚合函数 | SUM/AVG/COUNT OVER() | 累计值/移动平均 |
分布函数 | CUME_DIST/PERCENT_RANK | 数据分布分析 |
前后函数 | LAG/LEAD | 环比增长/上期对比 |
SELECT VERSION(); 查看数据库版本-- 创建示例表
CREATE TABLE sales (
sales_id INT PRIMARY KEY,
salesperson VARCHAR(20),
region VARCHAR(10),
amount DECIMAL(10,2),
sale_date DATE
);
-- 插入测试数据
INSERT INTO sales VALUES
(1, '张三', '华东', 15800, '2023-06-01'),
(2, '李四', '华南', 24500, '2023-06-02'),
(3, '王五', '华东', 18200, '2023-06-03'),
(4, '赵六', '华北', 31500, '2023-06-04'),
(5, '魏七', '华东', 22700, '2023-06-05');
-- 按地区分区排名
SELECT
salesperson,
region,
amount,
ROW_NUMBER() OVER (PARTITION BY region ORDER BY amount DESC) AS region_rank
FROM sales;执行结果:
salesperson | region | amount | region_rank |
|---|---|---|---|
赵六 | 华北 | 31500.00 | 1 |
李四 | 华南 | 24500.00 | 1 |
张三 | 华东 | 22700.00 | 1 |
王五 | 华东 | 18200.00 | 2 |
魏七 | 华东 | 15800.00 | 3 |
技巧延伸:
WHERE region_rank BETWEEN 6 AND 10实现高效分页ROW_NUMBER() = 1筛选最新记录-- 创建订单表
CREATE TABLE orders (
order_id INT PRIMARY KEY,
user_id INT,
order_amount DECIMAL(10,2),
order_date DATE
);
-- 插入测试数据
INSERT INTO orders VALUES
(1, 101, 1500, '2023-06-01'),
(2, 102, 2300, '2023-06-01'),
(3, 101, 800, '2023-06-02'),
(4, 103, 4500, '2023-06-03'),
(5, 102, 1200, '2023-06-03');
-- 按日期累计统计
SELECT
order_date,
SUM(order_amount) OVER (ORDER BY order_date) AS running_total,
SUM(order_amount) OVER (ORDER BY order_date
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg_3d
FROM orders
GROUP BY order_date;执行结果:
order_date | running_total | moving_avg_3d |
|---|---|---|
2023-06-01 | 3800.00 | 3800.00 |
2023-06-02 | 4600.00 | 4600.00 |
2023-06-03 | 10300.00 | 7600.00 |
高级用法:
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW实现7日均线SUM() OVER (PARTITION BY MONTH(order_date))按月分区-- 创建员工表
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
name VARCHAR(20),
department VARCHAR(20),
salary DECIMAL(10,2),
hire_date DATE
);
-- 插入测试数据
INSERT INTO employees VALUES
(1, '陈强', '技术部', 25000, '2020-03-15'),
(2, '李娜', '市场部', 18000, '2021-07-22'),
(3, '王伟', '技术部', 32000, '2019-11-05'),
(4, '张敏', '财务部', 21000, '2022-02-18'),
(5, '赵刚', '市场部', 19500, '2020-09-30');
-- 多维度分析
SELECT
department,
name,
salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank,
SUM(salary) OVER (PARTITION BY department) AS dept_total,
salary/SUM(salary) OVER (PARTITION BY department) AS salary_ratio
FROM employees;执行结果:
department | name | salary | dept_rank | dept_total | salary_ratio |
|---|---|---|---|---|---|
技术部 | 王伟 | 32000.00 | 1 | 57000.00 | 0.5614 |
技术部 | 陈强 | 25000.00 | 2 | 57000.00 | 0.4386 |
市场部 | 赵刚 | 19500.00 | 1 | 37500.00 | 0.5200 |
市场部 | 李娜 | 18000.00 | 2 | 37500.00 | 0.4800 |
财务部 | 张敏 | 21000.00 | 1 | 21000.00 | 1.0000 |
业务价值:
SELECT
salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num,
RANK() OVER (ORDER BY salary DESC) AS rank,
DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank
FROM employees;SUM(sales) OVER (ORDER BY sale_date
RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW)通过以上内容,相信大家已经感受到窗口函数在数据分析中的强大威力,大大降低了SQL编写的难度。大家是否有其他更好的使用场景欢迎评论区沟通交流!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。