SQL Server中用UNION和ROW_NUMBER获取两表唯一Name值问题
解决你的SQL Server去重问题:UNION + ROW_NUMBER()异常排查与修复
嘿,我看你遇到了用ROW_NUMBER()和UNION提取唯一Name记录的问题,结果里Clare S的RN居然到了52,取RN=1时还没显示,这确实挺头疼的。咱们一步步来分析和解决:
问题根源排查
从你给出的rn>0结果来看,同一个Name出现了多个RN值(比如Clare S有RN=52和RN=1),大概率是以下两个原因:
- 字符串不一致:
View1的Title和Table2的Name可能存在细微差异,比如前后空格、大小写不同(比如Clare S和Clare S或者clare s),SQL Server默认会把这些当成不同的字符串,导致分区的时候被分到不同组,自然会生成多个RN=1的记录。 - 原始数据中该Name存在大量重复:比如Clare S在
cte1里实际有52条记录,所以RN会从1排到52,而你只看到了其中两条。
修复方案
方案1:统一字符串格式(解决最可能的字符串差异问题)
先对Name字段做归一化处理,去除前后空格并统一大小写,确保两个来源的字符串完全一致,再进行分区:
WITH cte1 AS ( -- 处理View1的数据,保留原始Name同时生成归一化版本 SELECT ID, Caseid, Title AS OriginalName, LTRIM(RTRIM(LOWER(Title))) AS NormalizedName FROM View1 UNION ALL -- 用UNION ALL比UNION高效,因为后续会用ROW_NUMBER去重,不需要提前去重 -- 处理Table2的数据 SELECT ID, CaseID, Name AS OriginalName, LTRIM(RTRIM(LOWER(Name))) AS NormalizedName FROM Table2 WHERE Party = 'Yes' ), cte2 AS ( SELECT ID, Caseid, OriginalName, -- 按归一化后的Name分区,按ID倒序取最新的一条 ROW_NUMBER() OVER (PARTITION BY NormalizedName ORDER BY ID DESC) AS rn FROM cte1 ) -- 只取每个归一化Name的第一条记录 SELECT ID, Caseid, OriginalName AS Name FROM cte2 WHERE rn = 1
方案2:用GROUP BY快速取唯一记录(如果不在乎取哪条ID)
如果你的业务允许任意保留同一个Name的一条记录(比如取最大ID的那条),可以直接用GROUP BY,写法更简洁:
SELECT MAX(ID) AS ID, -- 换成MIN(ID)可以取最早的记录 MAX(Caseid) AS Caseid, -- 从你的数据看同一个Name的Caseid都是相同的,MAX/MIN都可以 -- 这里用归一化后的Name分组,避免字符串差异 LTRIM(RTRIM(LOWER(Name))) AS Name FROM ( SELECT ID, Caseid, Title AS Name FROM View1 UNION ALL SELECT ID, CaseID, Name AS Name FROM Table2 WHERE Party = 'Yes' ) t GROUP BY LTRIM(RTRIM(LOWER(Name)))
验证方法:先确认Name的重复情况
你可以先跑下面的SQL,看看每个Name的实际记录数,以及是否有看起来相同但实际不同的字符串:
SELECT Name, COUNT(*) AS RecordCount, MIN(ID) AS MinID, MAX(ID) AS MaxID FROM ( SELECT ID, Caseid, Title AS Name FROM View1 UNION ALL SELECT ID, CaseID, Name AS Name FROM Table2 WHERE Party = 'Yes' ) t GROUP BY Name ORDER BY RecordCount DESC
如果看到有多个看起来一样的Name(比如Clare S和Clare S ),那就是字符串差异的问题,用方案1的归一化处理就能解决。
内容的提问来源于stack exchange,提问作者Roo
相关产品推荐
相关产品推荐

