SQL Server 2019中能否删除不同列构成重复的行(id3、id4)
当然可以删除id3和id4啦,不过得先明确你的重复判定逻辑——看起来是同一个name下,三个address字段的非空值集合完全一致(比如Jenny的id1是A、B,id3是B、A,顺序不同但内容一样;John的id2是C,id4是C,只是位置不同)。下面给你两种适配SQL Server 2019的靠谱实现方式:
方法1:通过排序拼接地址字段判定重复
这个思路是把每个name下的非空address字段按统一顺序排序后拼接成字符串,这样顺序不同但内容相同的组合就会被判定为重复,然后我们保留每个重复组里id最小的那条,删除其他的。
WITH CTE_Duplicates AS ( SELECT id, name, -- 把非空地址排序后拼接成唯一标识字符串 STRING_AGG(addr, ',') WITHIN GROUP (ORDER BY addr) AS combined_address FROM ( SELECT id, name, value AS addr FROM Table1 -- 把三个address列转成行,方便统一处理 UNPIVOT ( value FOR addr_col IN (address1, address2, address3) ) AS unpvt WHERE value IS NOT NULL -- 过滤空值,只考虑有效地址 ) AS addr_rows GROUP BY id, name ), CTE_Rank AS ( SELECT t.id, -- 给每个重复组的记录编号,最小id排第1 ROW_NUMBER() OVER (PARTITION BY cd.name, cd.combined_address ORDER BY t.id) AS rn FROM Table1 t JOIN CTE_Duplicates cd ON t.id = cd.id ) -- 删除编号大于1的记录(也就是重复组里除了最小id之外的记录) DELETE FROM CTE_Rank WHERE rn > 1;
方法2:通过哈希值匹配地址集合(更可靠)
如果你的地址里可能包含逗号这类会干扰拼接的字符,用哈希值来判定重复会更稳妥。我们还是先处理非空地址,然后生成排序后地址集合的哈希值,再匹配重复组:
WITH CTE_AddressSets AS ( SELECT id, name, COUNT(value) AS addr_count, -- 统计非空地址的数量,作为额外校验 -- 生成排序后地址集合的哈希值 HASHBYTES('SHA2_256', STRING_AGG(value, ',') WITHIN GROUP (ORDER BY value)) AS addr_hash FROM Table1 UNPIVOT ( value FOR addr_col IN (address1, address2, address3) ) AS unpvt WHERE value IS NOT NULL GROUP BY id, name ) DELETE t FROM Table1 t JOIN ( SELECT name, addr_hash, addr_count, MIN(id) AS keep_id -- 每个重复组保留最小的id FROM CTE_AddressSets GROUP BY name, addr_hash, addr_count HAVING COUNT(id) > 1 -- 只处理存在重复的组 ) AS dup_groups ON t.name = dup_groups.name -- 匹配当前记录的地址哈希值和数量 AND HASHBYTES('SHA2_256', STRING_AGG(value, ',') WITHIN GROUP (ORDER BY value)) = dup_groups.addr_hash AND COUNT(value) OVER (PARTITION BY t.id) = dup_groups.addr_count WHERE t.id != dup_groups.keep_id; -- 删除非保留id的记录
重要提醒
执行删除操作前一定要先把DELETE替换成SELECT语句,检查返回的记录是不是你想要删除的id3和id4!比如把第一个方法的最后一行改成SELECT * FROM CTE_Rank WHERE rn > 1;,确认无误后再执行删除,避免误删数据。
内容的提问来源于stack exchange,提问作者user618520
相关产品推荐
相关产品推荐

