如何在SQL中显示去重后的重复记录?附查询语句及结果
如何找出被SQL DISTINCT过滤掉的重复记录
嘿,我来帮你解决这个问题——你现在已经用DISTINCT拿到了唯一行,但想看看那些被过滤掉的重复原始记录对吧?这里有两种实用的方法,完全适配你的查询场景:
方法1:先定位重复组,再拉取原始行
核心思路是先找出哪些字段组合是重复的(也就是DISTINCT会合并的那些组),再关联回原始表拿到所有重复的行。
针对你的关联查询,SQL可以这么写:
-- 先找出所有重复的字段组合,统计重复次数 WITH DuplicateGroups AS ( SELECT r.CustomerId, o.ItemNumber, o.ItemIdentifier, o.ItemProductNumber, COUNT(*) AS 重复次数 FROM Owner o INNER JOIN Report r ON o.ReportId = r.ReportId GROUP BY r.CustomerId, o.ItemNumber, o.ItemIdentifier, o.ItemProductNumber HAVING COUNT(*) > 1 -- 只保留出现多次的组 ) -- 关联原始表,取出这些重复组的所有原始记录 SELECT r.CustomerId, o.ItemNumber, o.ItemIdentifier, o.ItemProductNumber FROM Owner o INNER JOIN Report r ON o.ReportId = r.ReportId INNER JOIN DuplicateGroups dg ON dg.CustomerId = r.CustomerId AND dg.ItemNumber = o.ItemNumber AND dg.ItemIdentifier = o.ItemIdentifier AND dg.ItemProductNumber = o.ItemProductNumber ORDER BY r.CustomerId, o.ItemNumber;
这样就能把所有原本会被DISTINCT合并的重复行都拉出来,还能看到每个组重复了多少次。
方法2:用窗口函数标记重复行
如果你想更灵活地标记每一行是否是重复项,窗口函数ROW_NUMBER()是个好选择:
WITH 带编号的行 AS ( SELECT r.CustomerId, o.ItemNumber, o.ItemIdentifier, o.ItemProductNumber, -- 按你要去重的字段分组,给每行编序号 ROW_NUMBER() OVER ( PARTITION BY r.CustomerId, o.ItemNumber, o.ItemIdentifier, o.ItemProductNumber ORDER BY r.ReportId -- 可以按ReportId排序,或者用(SELECT NULL)不指定顺序 ) AS 行序号 FROM Owner o INNER JOIN Report r ON o.ReportId = r.ReportId ) -- 行序号>1的就是重复行,去掉WHERE就能看到整个重复组的所有行 SELECT CustomerId, ItemNumber, ItemIdentifier, ItemProductNumber FROM 带编号的行 WHERE 行序号 > 1 ORDER BY CustomerId, ItemNumber;
要是你想对比原始重复数据和DISTINCT结果的差异,直接去掉WHERE 行序号 > 1,就能看到每个重复组的所有行(包括第一次出现的那行)。
关于你的结果里的NULL值
还要提一句:SQL里NULL和NULL会被视为相等的,所以那些全NULL的行如果重复,上面的方法也能把它们找出来。比如你结果里的CustomerId=7那两行是不同的(ItemNumber不一样),所以不会被DISTINCT过滤,但如果有两条完全一样的行,这俩方法都能精准定位。
内容的提问来源于stack exchange,提问作者String_Chez




