SQL Server视图如何去除单列重复值且不修改源表数据
问题根因
你之前写的自连接去重逻辑有两个核心错误,导致无法生效:
- 比较字段写错:
PS2.LSiteID < PS.LSiteID是用重复维度本身做大小比较,同一个LSiteID对应的多条记录该字段值完全相等,这个条件永远不会成立,子查询计数恒为0,等于没有加过滤规则。 - 子查询没有关联外层查询的匹配逻辑,也没有引入唯一字段做判断基准,本身逻辑闭环不成立。
推荐实现方案
用窗口函数ROW_NUMBER()是SQL Server下这类视图层按指定字段去重的最优方案,不会修改源表任何数据,性能也比自连接写法更好。逻辑是按LSiteID分区,借助你提到的全局唯一的ProjectNumber做排序基准,每个LSiteID分组只保留1条记录即可。
可直接替换原视图的创建语句:
CREATE VIEW dbo.v_LSitesGeo AS SELECT LSiteID, geographyColumn FROM ( SELECT PS.LSiteID, GEO.geographyColumn, ROW_NUMBER() OVER ( PARTITION BY PS.LSiteID ORDER BY PS.ProjectNumber -- 同LSiteID下默认取ProjectNumber最小的关联记录,需要倒序取最新的就在字段后加DESC ) AS row_seq FROM dbo.Project_SiteID_Lookup AS PS INNER JOIN dbo.Geocodio AS GEO ON GEO.ProjectCode = PS.ProjectNumber WHERE GEO.geographyColumn IS NOT NULL AND PS.LSiteID IS NOT NULL ) AS filtered WHERE row_seq = 1
方案说明
- 该写法完全在视图层实现过滤,源表
Project_SiteID_Lookup的重复数据不会做任何改动,符合你的要求。 - 如果对同一个LSiteID下保留哪条地理数据有明确规则,只需要修改窗口函数里
ORDER BY后的字段即可,比如需要保留最新创建的记录,就换成表内的创建时间字段倒序排序。 - 之所以不能直接用
DISTINCT,是因为DISTINCT会对LSiteID+geographyColumn的组合去重,如果同一个LSiteID对应不同的geographyColumn值,依然会返回重复的LSiteID,达不到按LSiteID维度去重的目的。
原自连接写法的修正版
如果你习惯用类同你之前尝试的自连接逻辑,可以用NOT EXISTS改写(性能比COUNT计数好),核心是把比较字段换成唯一的ProjectNumber:
CREATE VIEW dbo.v_LSitesGeo AS SELECT PS.LSiteID, GEO.geographyColumn FROM dbo.Project_SiteID_Lookup AS PS INNER JOIN dbo.Geocodio AS GEO ON GEO.ProjectCode = PS.ProjectNumber WHERE GEO.geographyColumn IS NOT NULL AND PS.LSiteID IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM dbo.Project_SiteID_Lookup AS PS2 WHERE PS2.LSiteID = PS.LSiteID AND PS2.ProjectNumber < PS.ProjectNumber -- 同LSiteID下只保留ProjectNumber最小的记录 )
内容的提问来源于stack exchange,提问作者traitortots
相关产品推荐
相关产品推荐

