使用ROW_NUMBER更新CTE未达预期,求SQL Server 2016解决方案
问题原因分析
你的问题核心在于ROW_NUMBER()的排序字段没有唯一性:
在CTE的ROW_NUMBER定义中,ORDER BY a04.AccountNumber ASC,但因为已经用PARTITION BY a04.AccountNumber分区,同一分区内的AccountNumber值完全相同(都是777782),这会导致SQL Server无法确定明确的排序规则,RN的分配是随机不稳定的——每次执行时,相同AccountNumber的行可能被分配不同的RN值,最终导致你更新了错误的行。
修正方案
修改ROW_NUMBER的ORDER BY子句,使用具有唯一性的字段(比如RecordId)来确定稳定的排序规则。比如你想保留最新的RecordId(最大的那个),就按RecordId降序排序,这样RN=1始终对应最大的RecordId行,RN>1就是需要置为非激活的行。
修正后的完整SQL代码:
;WITH CTE AS ( SELECT a04.RecordId, a04.AccountNumber, a04.PhoneType, a04.Active , RN = ROW_NUMBER() OVER(PARTITION BY a04.AccountNumber ORDER BY a04.RecordId DESC) FROM dbo.A04_AccountPhones a04 WHERE a04.PhoneType = 'RRT' AND a04.AccountNumber = 777782 ) UPDATE c SET c.Active = 0 FROM CTE c WHERE c.RN > 1; -- 验证更新结果 SELECT a04.RecordId, a04.AccountNumber, a04.PhoneType, a04.Active, a04.AreaCode, a04.TelephoneNumber , RN = ROW_NUMBER() OVER(PARTITION BY a04.AccountNumber ORDER BY a04.RecordId DESC) FROM dbo.A04_AccountPhones a04 WHERE a04.PhoneType = 'RRT' AND a04.AccountNumber = 777782 ORDER BY a04.AccountNumber ASC, a04.RecordId DESC;
验证结果
更新后你会看到:
- RecordId=5803964(RN=1)的Active保持1
- RecordId=5802727(RN=2)和5533020(RN=3)的Active被置为0
完全符合你的预期。
内容的提问来源于stack exchange,提问作者Melinda
相关产品推荐
相关产品推荐

