SQL中非传统重复数据筛选:双向关联行的去重方案
处理双向关联重复数据的优雅去重方法
这确实是处理关联类数据时非常常见的场景——双向配对被存成两行,但我们只需要保留其中一组就行。我来分享几个实用且优雅的解决方案,适配大多数主流SQL方言:
方法一:利用比较运算符直接过滤(最简洁)
这是最直接高效的方式,核心思路是只保留id1小于id2的行(反过来选大于的也行,保持规则一致就好)。这样不管双向配对怎么存储,只会留下其中一行:
SELECT id1, id2 FROM your_table WHERE id1 < id2;
原理说明
比如你的示例数据里,ABC < DEF条件成立,这行会被保留;而DEF < ABC不成立,就会被过滤掉。如果你的ID是数字类型,这个逻辑同样适用。要是担心有NULL值,可以额外加个AND id1 IS NOT NULL AND id2 IS NOT NULL避免异常。
方法二:窗口函数分组去重(更灵活)
如果你的需求不止是去重,还需要自定义保留哪一行(比如保留最早插入的、或某一列有特定值的行),窗口函数会是更好的选择。我们可以用LEAST()和GREATEST()(大部分数据库支持)把双向配对统一成唯一的分组键,再用ROW_NUMBER()标记每组内的行,最后只取第一行:
SELECT id1, id2 FROM ( SELECT id1, id2, ROW_NUMBER() OVER ( PARTITION BY LEAST(id1, id2), GREATEST(id1, id2) ORDER BY id1 -- 这里可以换成你需要的排序规则,比如创建时间 create_time ) AS row_num FROM your_table ) AS filtered WHERE row_num = 1;
兼容小提示
如果你的数据库不支持LEAST()和GREATEST()(比如SQL Server),可以用CASE语句替代:
-- 替代LEAST(id1, id2) CASE WHEN id1 < id2 THEN id1 ELSE id2 END -- 替代GREATEST(id1, id2) CASE WHEN id1 > id2 THEN id1 ELSE id2 END
总结
- 如果你只需要简单去重,方法一是最优解,代码简洁且性能最好,不需要子查询或窗口函数;
- 如果你需要控制保留哪一行,方法二的灵活性更高,能应对更复杂的业务规则。
内容的提问来源于stack exchange,提问作者lilerer
相关产品推荐
相关产品推荐

