在SQL查询中,PARTITION BY和GROUP BY都是用于分组的关键字,但两者的运行逻辑和适用场景有本质区别,很多开发者在初学窗口函数时容易混淆这两个概念,导致查询结果不符合预期。

GROUP BY的核心逻辑
GROUP BY是标准SQL聚合查询的关键字,它的作用是将表中具有相同分组字段值的行合并成一行,最终返回的结果行数等于分组的数量。使用GROUP BY时,查询的SELECT子句只能包含分组字段和聚合函数(如SUM、COUNT、AVG等),不能直接返回原表的明细字段。
比如我们有一张订单表order_info,包含字段order_id(订单ID)、user_id(用户ID)、order_amount(订单金额),现在要统计每个用户的订单总金额,使用GROUP BY的查询如下:
-- 统计每个用户的订单总金额
SELECT
user_id,
SUM(order_amount) AS total_amount,
COUNT(order_id) AS order_count
FROM order_info
GROUP BY user_id;
上述查询执行后,每个user_id只会对应一行结果,原表中同一个用户的多条订单记录会被合并,无法直接看到单条订单的明细信息。
PARTITION BY的核心逻辑
PARTITION BY是窗口函数的配套关键字,它不会改变原查询结果的行数,只是为每一行数据划分一个独立的计算窗口,窗口函数会在这个窗口内完成计算,最终每一行都会保留自己的原始明细,同时附带窗口函数的计算结果。
同样用上面的订单表举例,如果我们要在保留每一条订单明细的同时,加上该订单所属用户的订单总金额,就可以用PARTITION BY配合SUM窗口函数实现:
-- 保留订单明细,同时统计每个用户的订单总金额
SELECT
order_id,
user_id,
order_amount,
SUM(order_amount) OVER (PARTITION BY user_id) AS user_total_amount
FROM order_info;
上述查询执行后,结果行数和原订单表的行数完全一致,每一行都包含完整的订单明细,同时user_total_amount字段会显示对应用户的订单总金额。
两者的核心差异对比
为了更清晰地区分两者的差异,我们可以从以下几个维度对比:
| 对比维度 | GROUP BY | PARTITION BY |
|---|---|---|
| 结果行数 | 合并分组,行数等于分组数 | 不改变行数,和原查询行数一致 |
| 返回内容 | 只能返回分组字段和聚合结果 | 可以保留原表所有明细字段,同时返回窗口计算结果 |
| 使用场景 | 需要分组聚合统计,不需要明细的场景 | 需要保留明细,同时做分组统计的场景 |
| 配套函数 | 配合SUM、COUNT等普通聚合函数使用 | 配合ROW_NUMBER、RANK、SUM等窗口函数使用 |
窗口函数的运行原理
窗口函数的执行逻辑可以分为三步:
- 第一步:执行FROM和WHERE子句,筛选出符合条件的基础数据行
- 第二步:根据PARTITION BY指定的字段对数据行进行分区,相同字段值的行会被划分到同一个窗口
- 第三步:在每个窗口内,按照ORDER BY指定的排序规则对行排序,再执行窗口函数计算,将结果附加到每一行上
需要注意的是,窗口函数只能出现在SELECT子句中,不能用于WHERE、GROUP BY等子句,因为窗口函数的执行顺序在这些子句之后。
常见使用误区
很多开发者会误以为PARTITION BY和GROUP BY可以互相替换,实际上两者的适用场景完全不同。如果需要的是分组后的聚合汇总结果,不需要明细,就用GROUP BY;如果需要在保留所有明细的同时,给每一行加上分组统计的结果,就用PARTITION BY配合窗口函数。如果错误地在需要明细的场景用了GROUP BY,就会丢失原始数据;如果在只需要聚合结果的场景用了PARTITION BY,会导致结果冗余,增加后续处理成本。
另外,PARTITION BY可以省略,如果省略的话,整个查询结果会被当作一个大的窗口,窗口函数会基于所有行进行计算,比如要计算所有订单的总金额,同时保留每一条订单明细,就可以这样写:
-- 保留订单明细,同时统计所有订单的总金额
SELECT
order_id,
user_id,
order_amount,
SUM(order_amount) OVER () AS all_total_amount
FROM order_info;
SQLPARTITION_BYGROUP_BY窗口函数修改时间:2026-06-08 21:21:29