如何基于自定义条件识别并移除SQL数据表中的隐式重复行
解决基于自定义规则的隐式重复行移除问题
针对你遇到的这种需要依据特定业务规则识别并移除隐式重复行的场景,我整理了一个适配SQL Server的解决方案,完美匹配你提出的三个去重规则。
原始数据情况
先回顾一下我们要处理的原始数据表:
| ID | COUNTRY | NAME | UNITS |
|---|---|---|---|
| 1000 | Canada | Andy | 1 |
| 1000 | Canada | Andy | 2 |
| 1000 | USA | Andy | 3 |
| 1000 | China | Bob | 3 |
| 2000 | Canada | Chase | 2 |
| 2000 | Canada | David | 3 |
| 2000 | USA | David | 4 |
| 3000 | Canada | John | 1 |
| 3000 | USA | John | 1 |
| 3000 | China | Dave | 3 |
明确去重规则
我们需要执行三个核心去重逻辑:
- 规则1(ID=1000,NAME=Andy):计算Andy关联国家的Units总和,总和相同时保留字母排序靠前的国家;若USA总和更大则保留USA。这里Andy在Canada的总和是
1+2=3,USA也是3,总和相同,所以保留Canada的所有行。 - 规则2(ID=2000,NAME=David):对比David在不同国家的Units数值,保留数值更大的USA对应的行。
- 规则3(ID=3000,NAME=John):John关联的两个国家Units数值相同,保留字母排序靠前的Canada对应的行。
SQL实现方案
我们可以利用窗口函数来计算分组总和并生成排序标识,从而精准筛选符合规则的行。以下是完整的代码:
1. 创建并填充临时表
首先创建临时表(注意原DDL中的type字段对应数据表的COUNTRY,已修正字段名):
CREATE TABLE #tmptbl ( id INT, country VARCHAR(20), name VARCHAR(20), qty INT ) INSERT INTO #tmptbl VALUES (1000, 'Canada', 'Andy', 1), (1000, 'Canada', 'Andy', 2), (1000, 'USA', 'Andy', 3), (1000, 'China', 'Bob', 3), (2000, 'Canada', 'Chase', 2), (2000, 'Canada', 'David', 3), (2000, 'USA', 'David', 4), (3000, 'Canada', 'John', 1), (3000, 'USA', 'John', 1), (3000, 'China', 'Dave', 3);
2. 执行去重查询
使用CTE(公共表表达式)结合窗口函数来实现规则:
WITH ranked_data AS ( SELECT *, -- 计算每个ID+NAME+COUNTRY组合的Units总和 SUM(qty) OVER (PARTITION BY id, name, country) AS country_total, -- 给每个ID+NAME分组内的国家排序:先按总和降序,再按国家字母升序 ROW_NUMBER() OVER ( PARTITION BY id, name ORDER BY SUM(qty) OVER (PARTITION BY id, name, country) DESC, country ASC ) AS rn FROM #tmptbl ) SELECT id, country, name, qty FROM ranked_data WHERE rn = 1 -- 只保留每个分组中排名第一的国家的所有行 ORDER BY id, name, country;
最终输出结果
执行上述查询后,得到完全符合预期的去重结果:
| ID | COUNTRY | NAME | QTY |
|---|---|---|---|
| 1000 | Canada | Andy | 1 |
| 1000 | Canada | Andy | 2 |
| 1000 | China | Bob | 3 |
| 2000 | Canada | Chase | 2 |
| 2000 | USA | David | 4 |
| 3000 | Canada | John | 1 |
| 3000 | China | Dave | 3 |
逻辑解释
SUM(qty) OVER (PARTITION BY id, name, country):计算每个国家对对应ID+NAME的Units贡献总和,用于规则中的数值对比。ROW_NUMBER():在每个ID+NAME分组内,先按国家总和从大到小排序,总和相同时按国家字母顺序升序排序,排名第一的国家就是我们需要保留的目标。- 最后筛选
rn=1的行,就能得到所有符合规则的非重复行。
内容的提问来源于stack exchange,提问作者Shantanu
相关产品推荐
相关产品推荐

