SQL 中的 Window Function:数据分析优化技巧
Source: Dev.to

大家好,数据和后端的同事们!在使用 SQL 时,大家一定都已经非常熟悉 GROUP BY。虽然功能强大,但 GROUP BY 有一个致命的缺点:它会把行“合并”,导致丢失原始数据每行的细节。
如果老板要求:“把每个订单的详细信息以及当月的总收入放在同一行”,该怎么办?这时 Window Function(窗口函数) 就大显身手了!
1. Window Function 是什么?
Window Function 允许对与当前行相关的一组行(称为“窗口”)进行计算,且不改变返回的行数。
基本结构
为了让 SQL 知道你正在使用 Window Function,必须使用 OVER() 子句。OVER() 中通常包含:
PARTITION BY– 将数据划分为组(类似GROUP BY,但不合并行)。ORDER BY– 在每个组内对数据进行排序。ROWS/RANGE– 定义更窄的窗口框架(例如:仅计算最近 3 行的总和)。
2. 平滑窗口函数类型
A. 聚合窗口函数(Aggregate Window Functions)
仍然是 SUM、AVG、COUNT、MAX、MIN,但与 OVER() 一起使用。
示例:计算全年每日累计收入总额
SELECT
MaDonHang,
NgayDatHang,
TongTien,
SUM(TongTien) OVER (
PARTITION BY YEAR(NgayDatHang)
ORDER BY NgayDatHang
) AS TongLuyKeNam
FROM DonHang;
B. 排名窗口函数(Ranking Window Functions)
用于查找“Top N”产品、优秀员工等场景。
| 函数 | 描述 |
|---|---|
ROW_NUMBER() | 连续编号 1, 2, 3, …(不考虑值相同的情况)。 |
RANK() | 值相等时排名相同,但会跳过后续排名(例如:1, 2, 2, 4)。 |
DENSE_RANK() | 值相等时排名相同,且不跳过后续排名(例如:1, 2, 2, 3)。 |
示例:对每个类别的畅销产品进行排名
SELECT
DanhMuc,
TenSanPham,
TongSoLuongBan,
RANK() OVER (
PARTITION BY DanhMuc
ORDER BY TongSoLuongBan DESC
) AS HangSanPham
FROM SanPhamBanChay;
C. 值窗口函数(Value Window Functions)
获取相对于当前行的前一行或后一行的值——对计算环比、同比等波动非常有用。
LAG()– 获取前一行的值。LEAD()– 获取后一行的值。
示例:比较本月与上月的销售额
SELECT
Thang,
DoanhSo,
LAG(DoanhSo, 1, 0) OVER (ORDER BY Thang) AS DoanhSoThangTruoc,
DoanhSo - LAG(DoanhSo, 1, 0) OVER (ORDER BY Thang) AS ChenhLech
FROM BaoCaoDoanhSo;
3. 性能优化技巧
- Index 是关键 – 确保在
PARTITION BY和ORDER BY中使用的列已经建立了合适的索引;否则 DB 将不得不手动排序,消耗资源。 - 限制过宽的窗口帧 – 在大数据集上避免使用
UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING,除非确实需要。 - 结合 CTE (
WITH ... AS) – 当需要多个复杂的 Window Function 时,使用 CTE 将其拆分,可使代码更易阅读,且 DB 能够更好地优化 Execution Plan。
🎯 总结
与其编写冗长且运行缓慢的子查询,窗口函数提供了简洁的语法和卓越的执行速度。对于数据分析或后端报表处理等工作,这是一项必备技能。
进一步探索: 如果想练习 SQL 题目、优化查询或进行数据库设计,欢迎访问博客 ITPrep,立即提升你的技能!