在SQL数据处理过程中,分组统计是高频需求,但传统的GROUP BY操作会将相同分组的多行数据合并为一行,导致最终结果的行数少于原始数据。如果需要在保留所有原始行的基础上,同时获取每个分组对应的统计值,窗口函数就是最合适的解决方案。

窗口函数的基本语法
窗口函数的核心是通过OVER子句定义计算范围,基本语法格式如下:
函数名(字段) OVER (
[PARTITION BY 分组字段]
[ORDER BY 排序字段 [ASC|DESC]]
[窗口帧定义]
) AS 别名
其中PARTITION BY用来指定分组的维度,作用和GROUP BY类似,但不会合并行;ORDER BY用来指定分组内的排序规则;窗口帧定义可以限定计算的范围,不指定的话默认计算整个分组的所有行。
常用聚合函数结合窗口函数实现分组统计
SUM、COUNT、AVG、MAX、MIN这些聚合函数都可以和窗口函数结合使用,在不改变行数的前提下完成分组统计。
示例数据准备
假设我们有一张销售记录表sales,结构如下:
| id | region | salesperson | amount |
|---|---|---|---|
| 1 | 华东 | 张三 | 1500 |
| 2 | 华东 | 李四 | 2000 |
| 3 | 华北 | 王五 | 1800 |
| 4 | 华东 | 赵六 | 1200 |
| 5 | 华北 | 钱七 | 2200 |
按地区分组统计销售总额
如果需要保留每一行销售记录,同时新增一列显示每个地区的总销售额,可以使用以下SQL:
SELECT
id,
region,
salesperson,
amount,
-- 按地区分组计算销售总额,不改变原行数
SUM(amount) OVER (PARTITION BY region) AS region_total_amount
FROM sales;
执行结果如下:
| id | region | salesperson | amount | region_total_amount |
|---|---|---|---|---|
| 1 | 华东 | 张三 | 1500 | 4700 |
| 2 | 华东 | 李四 | 2000 | 4700 |
| 3 | 华北 | 王五 | 1800 | 4000 |
| 4 | 华东 | 赵六 | 1200 | 4700 |
| 5 | 华北 | 钱七 | 2200 | 4000 |
可以看到原始5行数据全部保留,同时每一行都带有对应地区的总销售额。
按地区分组统计销售人数和平均销售额
同样可以实现分组计数和平均值计算:
SELECT
id,
region,
salesperson,
amount,
-- 按地区分组统计销售人数
COUNT(*) OVER (PARTITION BY region) AS region_person_count,
-- 按地区分组计算平均销售额
AVG(amount) OVER (PARTITION BY region) AS region_avg_amount
FROM sales;
窗口函数与传统GROUP BY的差异
两者的核心差异在于是否改变原数据的行数:
- GROUP BY会将相同分组的行合并为一行,最终结果行数等于分组数,无法直接保留原始行的其他字段信息,除非所有字段都参与分组。
- 窗口函数不会改变原数据的行数,每一行都会保留,同时可以在新增列中展示分组统计结果,适合需要同时查看明细和统计值的场景。
注意事项
使用窗口函数时需要注意,OVER子句中的PARTITION BY是可选的,如果不指定则会把整个表作为一个分组计算统计值。另外窗口帧的定义如果不指定,默认是RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING,即计算整个分组的所有行,如果需要按排序后的累计值计算,可以调整窗口帧范围。
-- 按地区分组,按销售额升序计算累计销售额
SELECT
id,
region,
salesperson,
amount,
SUM(amount) OVER (
PARTITION BY region
ORDER BY amount
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS region_cumulative_amount
FROM sales;
SQL窗口函数分组统计over_clause修改时间:2026-07-20 07:09:11