基于ANON ID和USER ID两列的SQL重复数据删除方案咨询
解决基于ANON ID和USER ID任意重复的去重问题
首先我得先明确下你的需求:你想要保留的行,是那些ANON ID在整个表中只出现一次,同时USER ID也只出现一次的行?从你给出的示例(保留第1、4、6、7行)来看,应该是这个逻辑——只要某行的ANON ID在其他行存在,或者USER ID在其他行存在,就把这行删掉。
如果是这样的话,用窗口函数就能轻松解决,不需要复杂的rownum逻辑。下面是具体的SQL实现:
方法一:用窗口函数筛选唯一出现的ID
我们可以先计算每个ANON ID和USER ID在表中的出现次数,然后只保留两者出现次数都为1的行:
WITH id_occurrences AS ( SELECT ANON_ID, USER_ID, -- 计算当前ANON ID的总出现次数 COUNT(*) OVER (PARTITION BY ANON_ID) AS anon_total, -- 计算当前USER ID的总出现次数 COUNT(*) OVER (PARTITION BY USER_ID) AS user_total FROM your_table_name -- 替换成你的表名 ) SELECT ANON_ID, USER_ID FROM id_occurrences WHERE anon_total = 1 AND user_total = 1;
这个CTE(公共表表达式)会给每一行标记出对应的ANON ID和USER ID的出现次数,最后我们筛选出两个计数都为1的行,就是你要保留的唯一实例。
如果你需要更灵活的保留规则(比如重复ANON ID中选一行)
如果你的实际需求不是完全删除所有重复ID的行,而是想在重复的ANON ID中保留一行,同时确保该行的USER ID也没有被其他ANON ID占用(类似二分图匹配),那逻辑会稍微复杂一点。比如:
- 对于每个ANON ID只保留一行
- 对于每个USER ID也只保留一行
这种情况可以用ROW_NUMBER()结合一些条件来实现,或者用递归CTE来做贪心匹配。举个简单的例子,优先保留ANON ID最早出现的行,同时确保USER ID不重复:
WITH ranked_rows AS ( SELECT ANON_ID, USER_ID, ROW_NUMBER() OVER (PARTITION BY ANON_ID ORDER BY (SELECT NULL)) AS anon_rank, ROW_NUMBER() OVER (PARTITION BY USER_ID ORDER BY (SELECT NULL)) AS user_rank FROM your_table_name ), selected AS ( -- 先选ANON ID和USER ID都唯一的行 SELECT ANON_ID, USER_ID FROM ranked_rows WHERE anon_rank = 1 AND user_rank = 1 UNION ALL -- 再选ANON ID唯一但USER ID重复的行(这里需要调整逻辑,根据你的优先级) SELECT ANON_ID, USER_ID FROM ranked_rows WHERE anon_rank = 1 AND user_rank > 1 AND ANON_ID NOT IN (SELECT ANON_ID FROM selected) AND USER_ID NOT IN (SELECT USER_ID FROM selected) ) SELECT * FROM selected;
不过这个逻辑需要根据你的实际优先级调整,比如你是优先保留ANON ID的第一个实例,还是USER ID的第一个实例。
但从你的描述来看,第一种方法应该完全符合你的需求——只要ANON ID或USER ID有重复,就删除该行,只保留两者都唯一的行。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

