Sum聚合分组与Partition by窗口函数的结果差异及正确用法咨询
咱们先直接说结论:你的第二种方法虽然得到了你预期的结果,但写法冗余;而第一种方法完全不符合你的需求,逻辑就错了。下面详细拆解两种方法的差异:
1. 第一种方法:逻辑错误,根本不是按bpm_no汇总
你的第一条SQL:
select a.bpm_no, sum(a.total_amount) from table a group by a.bpm_no, a.total_amount
这里的核心问题出在group by的字段选择上——你同时按bpm_no和total_amount分组,这意味着SQL会把同一个bpm_no下,total_amount值相同的行归为一组,然后统计每组的total_amount总和(其实就是该total_amount本身,因为同一组的total_amount都一样)。
举个实际例子:假设你的表a有这些数据:
| bpm_no | total_amount |
|---|---|
| B001 | 100 |
| B001 | 200 |
| B001 | 100 |
这条SQL执行后会得到:
| bpm_no | sum(a.total_amount) |
|---|---|
| B001 | 200 |
| B001 | 200 |
这显然不是你想要的“每个bpm_no的total_amount总和”(正确总和应该是400),所以你觉得“丢弃部分值”,本质是这条SQL的分组逻辑完全偏离了你的需求。
2. 第二种方法:结果正确,但写法冗余
你的第二条SQL:
select a.bpm_no, sum(a.total_amount) over (partition by a.bpm_no) from table a group by a.bpm_no,a.total_amount
这条SQL的执行逻辑是分两步的:
- 第一步执行
group by a.bpm_no,a.total_amount,得到和第一条SQL一样的分组结果(每个bpm_no+total_amount的组合行); - 第二步用窗口函数
sum(...) over (partition by a.bpm_no),对同一个bpm_no下的所有分组行的sum(a.total_amount)值再次求和,最终得到该bpm_no的总总和; - 最后每个分组行都会显示这个总总和,所以你能看到所有预期的记录(每个分组行都保留,且对应的总和是正确的)。
还是用刚才的例子,这条SQL会得到:
| bpm_no | sum(a.total_amount) over (partition by a.bpm_no) |
|---|---|
| B001 | 400 |
| B001 | 400 |
结果是对的,但写法绕了弯路——你完全不需要先group by,直接用窗口函数就能得到每个原行对应的bpm_no总和:
select a.bpm_no, sum(a.total_amount) over (partition by a.bpm_no) as total_sum from table a
这样原表有多少行,结果就有多少行,每行的total_sum都是对应bpm_no的总总和,写法更简洁直接。
正确的两种标准写法
根据你的需求,分两种场景:
如果你想要每个bpm_no仅显示一行,对应总总和,用
group by的正确写法是:select a.bpm_no, sum(a.total_amount) as total_sum from table a group by a.bpm_no(只按bpm_no分组,去掉total_amount即可)
如果你想要保留原表所有行,同时每行显示对应bpm_no的总总和,用窗口函数的正确写法是:
select a.bpm_no, a.total_amount, sum(a.total_amount) over (partition by a.bpm_no) as total_sum from table a(不需要group by,直接给原表加窗口函数)
内容的提问来源于stack exchange,提问作者Md Kamran Azam




