如何基于关联表的唯一ID返回正确的SUM计算结果?
解决SQL中多表关联导致的重复求和问题
嘿,我太懂你这个困扰了——这是SQL新手很容易踩的「重复关联导致求和翻倍」的坑!咱们先把问题根源理清楚:
你的m_user表中,ID=22222对应两条记录(分别是TG和MS平台)。当你把person、m_user、plan三张表直接关联时,plan里的两条记录(72小时和88小时)会分别和m_user的两条记录匹配,相当于生成了4条重复的plan记录:
- 22222 + 72
- 22222 + 72
- 22222 + 88
- 22222 + 88
这样SUM起来自然就是722 + 882 = 320,而不是你想要的72+88=160。之前尝试的DISTINCT和DISTINCT ON没用,是因为它们是在求和之后生效的,没办法改变已经重复计算的总和。
下面给你几个简单有效的解决方案:
方案1:先聚合plan表,再关联其他表
先把每个用户的计划小时数总和算好,再和用户表关联,从根源避免重复匹配:
SELECT ps.id, ps.name, ps.email, pl.total_hours AS hours FROM schema.person AS ps -- 先计算每个id的计划总时长 JOIN ( SELECT id, SUM(hours) AS total_hours FROM schema.plan WHERE client = 'CLIENT11' AND date BETWEEN '2017-12-01' AND '2017-12-31' GROUP BY id ) AS pl ON ps.id = pl.id -- 确保该用户存在于m_user表中 WHERE EXISTS ( SELECT 1 FROM schema.m_user AS usr WHERE usr.id = ps.id );
方案2:先对m_user的ID去重,再关联
如果想保留三表关联的结构,可以先把m_user里的重复ID去掉,再和其他表关联:
SELECT ps.id, ps.name, ps.email, SUM(pl.hours) AS hours FROM schema.person AS ps -- 只取m_user中唯一的ID JOIN (SELECT DISTINCT id FROM schema.m_user) AS usr ON ps.id = usr.id JOIN schema.plan AS pl ON usr.id = pl.id WHERE pl.client = 'CLIENT11' AND pl.date BETWEEN '2017-12-01' AND '2017-12-31' GROUP BY ps.id, ps.name, ps.email;
方案3:用CTE让逻辑更清晰(PostgreSQL友好)
如果你喜欢更模块化的写法,用CTE把各个步骤拆分出来,可读性更强:
WITH plan_totals AS ( -- 第一步:计算每个用户的计划总时长 SELECT id, SUM(hours) AS total_hours FROM schema.plan WHERE client = 'CLIENT11' AND date BETWEEN '2017-12-01' AND '2017-12-31' GROUP BY id ), unique_user_ids AS ( -- 第二步:获取m_user中所有唯一的用户ID SELECT DISTINCT id FROM schema.m_user ) -- 第三步:关联用户信息和计算好的总时长 SELECT ps.id, ps.name, ps.email, pt.total_hours AS hours FROM schema.person AS ps JOIN unique_user_ids AS uui ON ps.id = uui.id JOIN plan_totals AS pt ON ps.id = pt.id;
这三个方案都能解决你的问题,其中方案1和3的性能会更好一些,因为提前聚合了plan表,减少了关联的数据量。
内容的提问来源于stack exchange,提问作者M. Montoya
相关产品推荐
相关产品推荐

