SQL Server中用CTE标记重复记录的问题排查与解决
SQL Server 重复记录标记失效问题
需求说明
需标记重复记录,重复判定规则为Call_GUID、Call_Type_ID和Date字段值完全相同。仅将DateTime最早的第一条记录之外的重复记录的Dup_Flag1设为Y,第一条记录保持NULL。
初始数据
| DateTime | Call_Type_ID | Call_GUID | Dup_Flag1 | DupRank |
|---|---|---|---|---|
| 2023-09-21 09:28:01.370 | 12986 | 00A4AB00000100000000520883048B0A | NULL | 1 |
| 2023-09-21 09:35:08.270 | 12986 | 00A4AB00000100000000520883048B0A | NULL | 2 |
| 2023-09-21 09:35:29.887 | 12986 | 00A4AB00000100000000520883048B0A | NULL | 3 |
预期结果
| DateTime | Call_Type_ID | Call_GUID | Dup_Flag1 | DupRank |
|---|---|---|---|---|
| 2023-09-21 09:28:01.370 | 12986 | 00A4AB00000100000000520883048B0A | NULL | 1 |
| 2023-09-21 09:35:08.270 | 12986 | 00A4AB00000100000000520883048B0A | Y | 2 |
| 2023-09-21 09:35:29.887 | 12986 | 00A4AB00000100000000520883048B0A | Y | 3 |
实际错误结果
| DateTime | Call_Type_ID | Call_GUID | Dup_Flag1 | DupRank |
|---|---|---|---|---|
| 2023-09-21 09:28:01.370 | 12986 | 00A4AB00000100000000520883048B0A | Y | 1 |
| 2023-09-21 09:35:08.270 | 12986 | 00A4AB00000100000000520883048B0A | Y | 2 |
| 2023-09-21 09:35:29.887 | 12986 | 00A4AB00000100000000520883048B0A | Y | 3 |
原SQL语句
WITH Dups AS (SELECT "DateTime", Call_Type_ID, Call_GUID, Dup_Flag1, DupRank = ROW_NUMBER() OVER (PARTITION BY Call_GUID, Call_Type_ID, "Date" ORDER BY "DateTime" ASC) FROM #temp_records_SLS_U65_ALL WHERE Call_GUID = '00A4AB00000100000000520883048B0A') UPDATE #temp_records_SLS_U65_ALL SET Dup_Flag1 = 'Y' FROM #temp_records_SLS_U65_ALL AS t INNER JOIN Dups AS d ON t.Call_GUID = d.Call_GUID WHERE d.DupRank > 1;
问题分析与修正方案
问题原因
原语句仅通过Call_GUID关联临时表和CTE,会导致所有同Call_GUID的记录被批量关联——即使CTE中DupRank=1的记录,也会和临时表中3条记录全部匹配,最终所有记录都被误更新。
修正后的SQL语句
使用能唯一标识单条记录的字段组合(如DateTime+Call_Type_ID+Call_GUID)进行关联,确保只更新CTE中DupRank>1对应的具体记录:
WITH Dups AS ( SELECT "DateTime", Call_Type_ID, Call_GUID, DupRank = ROW_NUMBER() OVER (PARTITION BY Call_GUID, Call_Type_ID, "Date" ORDER BY "DateTime" ASC) FROM #temp_records_SLS_U65_ALL WHERE Call_GUID = '00A4AB00000100000000520883048B0A' ) UPDATE t SET t.Dup_Flag1 = 'Y' FROM #temp_records_SLS_U65_ALL AS t INNER JOIN Dups AS d ON t."DateTime" = d."DateTime" AND t.Call_Type_ID = d.Call_Type_ID AND t.Call_GUID = d.Call_GUID WHERE d.DupRank > 1;
补充说明
- 如果表中有主键(如自增ID),用主键关联比
DateTime更可靠,可避免DateTime存在重复值的情况。 - 若要批量处理所有
Call_GUID的重复记录,只需删除CTE中的WHERE Call_GUID = 'xxx'条件即可。
内容的提问来源于stack exchange,提问作者GLo
相关产品推荐
相关产品推荐

