You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL中使用GROUP BY与DISTINCT计算列SUM()结果异常问题

问题描述

我编写了如下查询语句:

select distinct ProdQty, JobCompletionDate, JobHead.JobNum from erp.JobHead 
inner join erp.LaborDtl on JobHead.JobNum = LaborDtl.JobNum and JobHead.Company = LaborDtl.Company
where JobCompletionDate = '2022-01-04' and JobHead.Company = 'TD' and LaborDtl.JCDept ='MS'

该语句可返回指定JobCompletionDate下,每个JobNum对应的ProdQty值,以下是返回结果的片段:

Prod QtyJobCompletionDateJobNum
122022-01-04198583
12022-01-04205388
22022-01-04205562

此处未粘贴完整结果表,核心逻辑清晰:我在查询中使用distinct是因为ProdQty通常存在重复条目,该关键字可剔除重复记录。

接下来我需要按JobCompletionDate执行GROUP BY分组,统计对应日期下ProdQty的总和,但对ProdQty字段使用SUM()时遇到问题:我通过Excel或计算器手动累加该列数值,得到正确结果为7201,但执行如下查询时:

select sum(distinct ProdQty) from erp.JobHead 
inner join erp.LaborDtl on JobHead.JobNum = LaborDtl.JobNum and JobHead.Company = LaborDtl.Company
where JobCompletionDate = '2022-01-04' and JobHead.Company = 'TD' and LaborDtl.JCDept ='MS'
group by JobCompletionDate

返回的结果为6660,与正确值不符。请问该问题产生的原因是什么?我的SQL写法存在什么错误?

问题原因
  • 核心错误是误用了SUM(DISTINCT 字段)语法:该语法的执行逻辑是对结果集中的ProdQty值做全局去重,相同数值仅保留1次参与求和,而非你预期的「先剔除重复的整行记录,再对保留行的ProdQty求和」。
  • 举个最直观的例子:如果两个不同JobNum的工单ProdQty都是12,SUM(DISTINCT ProdQty)只会把这个12计算1次,而你手动累加时两个工单的12会合计为24,结果必然偏小。你得到的6660比正确值少541,就是所有重复出现的ProdQty值被少算的总和。
  • 你最初写SELECT DISTINCT ProdQty, JobCompletionDate, JobHead.JobNum时,去重判断依据是三个字段的组合值:只要JobNum不同,哪怕ProdQty、JobCompletionDate完全一致,也会被判定为不同记录保留,这才是你需要的去重效果——你本来要剔除的是联表时一对多关系带出来的同一个JobNum的重复行,不是把生产数量相同的不同工单合并计算。
正确写法

不要在SUM函数内加DISTINCT,先完成行级去重再做聚合,两种常用写法都可以得到正确结果:

  1. 基于你最初的去重逻辑套一层子查询求和
select sum(ProdQty) from (
    select distinct ProdQty, JobCompletionDate, JobHead.JobNum 
    from erp.JobHead 
    inner join erp.LaborDtl on JobHead.JobNum = LaborDtl.JobNum and JobHead.Company = LaborDtl.Company
    where JobCompletionDate = '2022-01-04' and JobHead.Company = 'TD' and LaborDtl.JCDept ='MS'
) t
group by JobCompletionDate
  1. 先按工单维度聚合去重再求和(大表场景下性能更优)
select sum(ProdQty) from (
    select max(ProdQty) as ProdQty, JobCompletionDate
    from erp.JobHead 
    inner join erp.LaborDtl on JobHead.JobNum = LaborDtl.JobNum and JobHead.Company = LaborDtl.Company
    where JobCompletionDate = '2022-01-04' and JobHead.Company = 'TD' and LaborDtl.JCDept ='MS'
    group by JobHead.JobNum, JobCompletionDate
) t
group by JobCompletionDate

额外说明:你一开始需要加DISTINCT的根本原因,是LaborDtl表中同一个JobNum可能对应多条符合JCDept='MS'的记录,联表时会把JobHead的单条工单记录复制多份。如果业务上能保证每个符合筛选条件的JobNum在LaborDtl中仅对应1条记录,从根源上避免一对多联表产生的重复行,就不需要额外加去重逻辑。


内容的提问来源于stack exchange,提问作者Avery1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 09:57:19