Inner Join生成重复记录的原因及解决方法(附SQL示例)
为什么你的Inner Join查询会生成重复记录?怎么解决?
首先看你贴出来的示例数据,确实不会产生重复结果——两张表各有一条匹配的记录,Inner Join后应该只会返回一行。但你实际查询出重复的话,大概率是两张表中存在重复的匹配行,常见的情况有这几种:
AllowedUsers表中,同一个sUserCode='TM001'+sProdCode='1001'的记录有多条(比如不小心重复插入了)ProdMaster表中,同一个sProdCode='1001'+sProdStatus='pending'的记录有多条- 两张表都有对应重复行,Join之后产生了笛卡尔积,导致重复翻倍
针对这个问题,有几种可行的解决方式:
1. 快速去重:用DISTINCT关键字
最简单直接的方式,就是在SELECT后面加上DISTINCT,让数据库自动过滤掉完全重复的记录:
SELECT DISTINCT AU.sProdCode, AU.sProdName FROM AllowedUsers AU INNER JOIN ProdMaster PM ON AU.sProdCode = PM.sProdCode WHERE PM.sProdStatus = 'pending' AND AU.sUserCode = 'TM001'
这个方法适合快速解决查询结果重复的问题,不需要改动源数据。
2. 从根源解决:清理源表的重复数据
如果重复数据是业务上不合理的(比如系统不允许同一个用户重复关联同一个产品,或者同一个产品不该有多条pending状态的记录),那最好先清理源表的重复项:
- 检查
AllowedUsers的重复:执行SELECT sProdCode, sUserCode, COUNT(*) FROM AllowedUsers GROUP BY sProdCode, sUserCode HAVING COUNT(*) > 1,找出重复的用户-产品关联记录,然后删除多余的行 - 检查
ProdMaster的重复:执行SELECT sProdCode, sProdStatus, COUNT(*) FROM ProdMaster GROUP BY sProdCode, sProdStatus HAVING COUNT(*) > 1,找出重复的产品-状态记录,清理掉多余的
3. 用GROUP BY分组去重
如果需要对数据做聚合,或者只是想通过分组来实现去重,也可以用GROUP BY:
SELECT AU.sProdCode, AU.sProdName FROM AllowedUsers AU INNER JOIN ProdMaster PM ON AU.sProdCode = PM.sProdCode WHERE PM.sProdStatus = 'pending' AND AU.sUserCode = 'TM001' GROUP BY AU.sProdCode, AU.sProdName
注意:不同数据库对GROUP BY的语法要求不一样,比如MySQL在开启ONLY_FULL_GROUP_BY模式时,SELECT中的非聚合字段必须都出现在GROUP BY里,所以建议严格按照标准语法写,避免报错。
另外,你可以先排查一下哪张表有重复行:
- 查AllowedUsers的匹配记录数:
SELECT COUNT(*) FROM AllowedUsers WHERE sUserCode='TM001' AND sProdCode='1001' - 查ProdMaster的匹配记录数:
SELECT COUNT(*) FROM ProdMaster WHERE sProdCode='1001' AND sProdStatus='pending'
如果其中某条查询返回的数大于1,那就是这张表的重复导致的问题啦。
内容的提问来源于stack exchange,提问作者Sixthsense
相关产品推荐
相关产品推荐

