如何结合GROUP BY与窗口函数实现分组计算及二次聚合
我来帮你搞定这个需求,咱们分两步来实现,逻辑清晰又高效:
第一步:计算每个ID1+ID2组合的Value3
要让同一ID1和ID2组合的所有行都带上相同的Value3,用窗口函数是最直接的方式——它能在不改变原表行数的前提下,计算分组统计值。
具体来说,用SUM(Value2) OVER (PARTITION BY ID1, ID2)得到每个ID1+ID2组合的Value2总和,再对这个总和取平方就是Value3。
示例SQL(生成带Value3的中间表):
WITH a_with_value3 AS ( SELECT ID1, ID2, Value1, Value2, POWER(SUM(Value2) OVER (PARTITION BY ID1, ID2), 2) AS Value3 FROM 表a ) SELECT * FROM a_with_value3;
执行后就能得到你需要的带Value3的结果:
ID1 ID2 Value1 Value2 Value3
1 1 2 2 64
1 1 3 2 64
1 1 2 4 64
1 2 1 2 4
这里用POWER()函数计算平方,你也可以用SUM(...) * SUM(...)替代,效果完全一致:
(SUM(Value2) OVER (PARTITION BY ID1, ID2)) * (SUM(Value2) OVER (PARTITION BY ID1, ID2)) AS Value3
第二步:按ID1分组计算sum(Value1*Value3)
基于上面的中间表,我们直接按ID1分组,计算Value1*Value3的总和即可。把两步整合到一起的完整SQL如下:
WITH a_with_value3 AS ( SELECT ID1, Value1, POWER(SUM(Value2) OVER (PARTITION BY ID1, ID2), 2) AS Value3 FROM 表a ) SELECT ID1, SUM(Value1 * Value3) AS Result FROM a_with_value3 GROUP BY ID1;
执行这个查询,ID1=1时的结果就是2*64 + 3*64 + 2*64 + 1*4 = 128+192+128+4 = 452,和你给出的示例完全匹配。
兼容老版本数据库的备选方案
如果你的数据库不支持窗口函数(比如MySQL 5.x及更早版本),可以用关联子查询来实现:
SELECT t1.ID1, SUM(t1.Value1 * t2.Value3) AS Result FROM 表a t1 JOIN ( SELECT ID1, ID2, POWER(SUM(Value2), 2) AS Value3 FROM 表a GROUP BY ID1, ID2 ) t2 ON t1.ID1 = t2.ID1 AND t1.ID2 = t2.ID2 GROUP BY t1.ID1;
这个方案先分组计算每个ID1+ID2的Value3,再通过JOIN把Value3关联回原表的每一行,最后聚合计算总和,逻辑和窗口函数版本一致,只是效率稍低一些。
内容的提问来源于stack exchange,提问作者bublitz

