如何在分组聚合SQL中计算各分组占全局总和的占比?
分组聚合SQL优化:计算分组占全局总和的比例
现有一条分组聚合SQL,已实现按指定字段分组统计各分组的OrcaItem.Vr_TotalLiquido总和(别名Vr_Liquido),现需计算每个分组的Vr_Liquido占全局Vr_Liquido总和的比例。已知可通过子查询实现,但希望找到更优方案。
当前查询返回简化示例
id|sum 1| 10 2| 50 3| 80 4| 20 5| 60
期望返回结果(全局总和为220)
id|sum| % 1| 10|10/220 2| 50|50/220 3| 80|80/220 4| 20|20/220 5| 60|60/220
最优方案:使用窗口函数替代子查询
无需额外子查询,直接用**窗口函数SUM() OVER ()**即可高效计算全局总和,避免重复扫描数据表,性能更优。
修改后的完整SQL
Select OrcaItem.Cd_Produto, OrcaItem.Ds_Produto, OrcaItem.Cd_Produto || ' - ' || OrcaItem.Ds_Produto CdDs_Produto, Estoque.Qt_Disponivel, Sum(OrcaItem.Qt_Vendida) Qt_Vendida, Sum(OrcaItem.Vr_TotalLiquido) Vr_Liquido, -- 新增:计算分组占全局总和的比例(数值形式,保留4位小数) Cast(Sum(OrcaItem.Vr_TotalLiquido) / Sum(Sum(OrcaItem.Vr_TotalLiquido)) OVER () As Numeric(10,4)) Pc_Liquido, -- 可选:按示例格式显示为"分子/分母"的字符串形式 Cast(Sum(OrcaItem.Vr_TotalLiquido) As Varchar) || '/' || Cast(Sum(Sum(OrcaItem.Vr_TotalLiquido)) OVER () As Varchar) Pc_Liquido_Text, Cast(Sum( Case :piTipoCusto When 0 Then (Produto.Vr_CustoAtual * OrcaItem.Qt_Vendida) When 1 Then (OrcaItem.Vr_CustoAtual * OrcaItem.Qt_Vendida) When 2 Then (OrcaItem.Vr_CustoFin * OrcaItem.Qt_Vendida) When 3 Then (Produto.Vr_UltPcoCompra * OrcaItem.Qt_Vendida) End ) As Numeric(15,2)) Vr_Custo, Cast(Sum( Case :piTipoCusto When 0 Then OrcaItem.Vr_TotalLiquido - (Produto.Vr_CustoAtual * OrcaItem.Qt_Vendida) When 1 Then OrcaItem.Vr_TotalLiquido - (OrcaItem.Vr_CustoAtual * OrcaItem.Qt_Vendida) When 2 Then OrcaItem.Vr_TotalLiquido - (OrcaItem.Vr_CustoFin * OrcaItem.Qt_Vendida) When 3 Then OrcaItem.Vr_TotalLiquido - (Produto.Vr_UltPcoCompra * OrcaItem.Qt_Vendida) End ) As Numeric(15,2)) Vr_Lucro, Sum( Case :piTipoCusto When 0 Then OrcaItem.Vr_TotalLiquido - (Produto.Vr_CustoAtual * OrcaItem.Qt_Vendida) When 1 Then OrcaItem.Vr_TotalLiquido - (OrcaItem.Vr_CustoAtual * OrcaItem.Qt_Vendida) When 2 Then OrcaItem.Vr_TotalLiquido - (OrcaItem.Vr_CustoFin * OrcaItem.Qt_Vendida) When 3 Then OrcaItem.Vr_TotalLiquido - (Produto.Vr_UltPcoCompra * OrcaItem.Qt_Vendida) End ) / Sum(OrcaItem.Vr_TotalLiquido) * 100 Pc_Lucro, Produto.Cd_Linha, Linha.Ds_Linha, Produto.Cd_Grupo, Grupo.Ds_Grupo From OrcaItem Inner Join Orca On Orca.Nr_Orcamento = OrcaItem.Nr_Orcamento Inner Join Estoque On Estoque.Cd_Produto = OrcaItem.Cd_Produto Inner Join Produto On Produto.Cd_Produto = OrcaItem.Cd_Produto Inner Join Linha On Linha.Cd_Linha = Produto.Cd_Linha Inner Join Grupo On Grupo.Cd_Linha = Produto.Cd_Linha And Grupo.Cd_Grupo = Produto.Cd_Grupo Where Orca.Fg_Situacao In ('F', 'R') And Orca.Dt_Atendido Between :piDt_Inicio And :piDt_Final Group By OrcaItem.Cd_Produto, OrcaItem.Ds_Produto, CdDs_Produto, Estoque.Qt_Disponivel, Produto.Cd_Linha, Linha.Ds_Linha, Produto.Cd_Grupo, Grupo.Ds_Grupo Order By Produto.Cd_Linha, Produto.Cd_Grupo, OrcaItem.Ds_Produto
关键说明
Sum(Sum(OrcaItem.Vr_TotalLiquido)) OVER ():内层Sum是分组聚合得到的每个分组的Vr_Liquido,外层Sum结合OVER ()(不指定分区,覆盖整个结果集)计算出全局总和。- 若需要百分比形式,可将数值比例乘以100,比如
Cast(Sum(OrcaItem.Vr_TotalLiquido)/Sum(Sum(OrcaItem.Vr_TotalLiquido)) OVER ()*100 As Numeric(10,2)) || '%' Pc_Liquido_Pct。
内容的提问来源于stack exchange,提问作者Roberto Henrique
相关产品推荐
相关产品推荐

