如何编写SQL查询返回无重复的同城市人员配对列表?
嘿,这个问题我太熟悉了——很多人刚开始写自连接查询的时候都会踩这个重复配对的坑!你遇到的重复问题,本质是因为自连接会同时返回(A,B)和(B,A)这两种方向相反的配对,而这其实是同一个组合,对吧?
先说说为什么你的初始查询会重复
假设你一开始写的是类似这样的查询:
SELECT a.name AS person1, b.name AS person2, a.city FROM people a JOIN people b ON a.city = b.city WHERE a.name != b.name;
这条语句会把同一个城市里的每两个人都配对两次:比如Alice和Bob在同一个城市,那么当a是Alice、b是Bob时会出现一条记录,当a是Bob、b是Alice时又会出现一条完全反向的记录,这就是你看到的重复数据。
正确的去重解决方案
要解决这个问题,核心是给配对加一个单向的约束,让每对人员只以一种顺序出现。最可靠的方式是用表的唯一主键(比如person_id,如果你的表有这个字段的话)来做判断,代码如下:
SELECT a.name AS person1, b.name AS person2, a.city FROM people a JOIN people b ON a.city = b.city WHERE a.person_id < b.person_id;
如果你的表没有唯一主键,只能用名字的话(注意:如果有同名的人,这个方法可能有问题,优先推荐用主键),可以这样写:
SELECT a.name AS person1, b.name AS person2, a.city FROM people a JOIN people b ON a.city = b.city WHERE a.name < b.name;
原理解释
通过a.person_id < b.person_id这个条件,我们强制只保留“第一个人的ID小于第二个人ID”的配对。这样一来,(Alice,Bob)会被保留,但(Bob,Alice)因为Bob的ID更大,会被WHERE条件过滤掉,完美避免了重复。
如果用名字的话,a.name < b.name是按字符串的字典序来判断的,同样能保证每对只出现一次。
额外提示
如果你的表还没有唯一主键,建议尽快添加一个(比如person_id INT AUTO_INCREMENT PRIMARY KEY),因为名字可能存在重复的情况,用主键来判断配对的唯一性会更准确,不会出现误判。
内容的提问来源于stack exchange,提问作者Alan Mark Kristensen

