SQL Server 2016中按ID分组,用details列末尾两位更新Number列的实现疑问
SQL Server 2016中按ID分组,用details列末尾两位更新Number列的实现疑问
哥们儿,这个需求当然可以实现!你之前的写法问题在于只是逐行处理了带斜杠的details行,但没做到按ID统一更新同组的所有行,所以才会留下同ID但Number值不一致的情况。咱们来一步步解决这个问题:
核心思路
首先得按ID分组,先提取每个ID对应的目标Number值(也就是该ID下带斜杠的details列最后两位),再用这个值批量更新同ID下的所有行,而不是逐行单独更新。
具体实现脚本
这里用CTE(公共表表达式)来先获取每个ID的目标值,再关联原表进行更新,逻辑清晰又容易维护:
-- 先定义每个ID对应的目标Number值 WITH TargetNumberPerID AS ( SELECT ID, RIGHT(details, 2) AS TargetNum FROM YourTable WHERE details LIKE '%/%' -- 只处理带斜杠的details行 GROUP BY ID, RIGHT(details, 2) -- 注:如果同一个ID下有多个带斜杠的details且末尾两位不同,这里会返回多个行 -- 这时候需要你根据业务规则调整,比如取最大/最小,或者按行的创建时间排序取最新的 ) -- 执行更新:按ID关联,把同ID的所有行Number统一更新为目标值 UPDATE t SET t.Number = tv.TargetNum FROM YourTable t INNER JOIN TargetNumberPerID tv ON t.ID = tv.ID -- 可选:只更新Number和目标值不一致的行,减少不必要的更新操作 WHERE t.Number <> tv.TargetNum
处理同一ID下多个带斜杠details的情况
如果你的业务场景中,同一个ID可能存在多个带斜杠的details行,且它们的末尾两位不同,那上面的脚本会因为一个ID对应多个目标值而出错。这时候可以用ROW_NUMBER()来指定取哪一个值,比如取最新的行(假设你有类似CreateTime的时间列):
WITH TargetNumberPerID AS ( SELECT ID, RIGHT(details, 2) AS TargetNum, -- 按CreateTime倒序,取每个ID的最新行的目标值 ROW_NUMBER() OVER (PARTITION BY ID ORDER BY CreateTime DESC) AS RowRank FROM YourTable WHERE details LIKE '%/%' ) UPDATE t SET t.Number = tv.TargetNum FROM YourTable t INNER JOIN TargetNumberPerID tv ON t.ID = tv.ID WHERE tv.RowRank = 1 -- 只取每个ID的第一个目标值(这里是最新的) AND t.Number <> tv.TargetNum
为什么你原来的写法没生效?
你之前的脚本是逐行更新:只给当前details带斜杠的行更新Number,但同ID下其他行(比如details是Temp的那行)完全没被触及,所以才会出现同ID但Number值不一样的情况。而咱们上面的写法是先按ID拿到统一的目标值,再批量更新同ID的所有行,正好解决了这个问题。
备注:内容来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

