SQL存储过程仅更新行一次问题排查(.NET Core+SSMS)
问题分析与解决方案
问题根源
SQL的UPDATE语句在单次执行时,同一目标行只会被更新一次——它会基于目标行的初始值,和关联的所有源数据进行计算,但不会像你预期的那样迭代更新。哪怕PedidosBorrados里有两行匹配记录,Inventory.Embarques的目标行只会用初始的TotalKilos和Percentage计算一次,不会先减第一行再减第二行。
解决方案
要实现逐步递减的效果,必须逐行处理PedidosBorrados的记录,每次更新都基于上一次更新后的最新值计算。以下是两种适配场景的方案:
方案1:游标逐行处理(严格按顺序更新)
如果业务要求必须按特定顺序逐步扣减重量,用游标是最直接的方式:
DECLARE @EmbarqueId INT, @Kilos DECIMAL(18,2) -- 声明游标,获取待处理记录(可添加排序字段保证处理顺序) DECLARE pedidos_cursor CURSOR FOR SELECT EmbarqueId, Kilos FROM dbo.PedidosBorrados WHERE Actualizado = 0 ORDER BY -- 此处添加排序字段,比如创建时间或业务优先级字段 OPEN pedidos_cursor FETCH NEXT FROM pedidos_cursor INTO @EmbarqueId, @Kilos WHILE @@FETCH_STATUS = 0 BEGIN -- 基于当前最新值更新Embarques UPDATE Inventory.Embarques SET Percentage = ((TotalKilos - @Kilos) * Percentage) / TotalKilos, TotalKilos = TotalKilos - @Kilos WHERE EmbarqueId = @EmbarqueId -- 标记当前记录为已处理,避免重复操作 UPDATE dbo.PedidosBorrados SET Actualizado = 1 WHERE EmbarqueId = @EmbarqueId AND Kilos = @Kilos FETCH NEXT FROM pedidos_cursor INTO @EmbarqueId, @Kilos END CLOSE pedidos_cursor DEALLOCATE pedidos_cursor
方案2:聚合更新(仅需最终结果)
如果业务不要求严格的逐步更新顺序,只需要最终重量是初始值减去所有待扣减的总和,可直接用聚合查询一次性更新:
UPDATE Inventory.Embarques SET Percentage = ((a.TotalKilos - b.TotalKilosToSubtract)*a.Percentage)/a.TotalKilos, TotalKilos = a.TotalKilos - b.TotalKilosToSubtract From Inventory.Embarques a INNER JOIN ( SELECT EmbarqueId, SUM(Kilos) AS TotalKilosToSubtract FROM dbo.PedidosBorrados WHERE Actualizado = 0 GROUP BY EmbarqueId ) b ON a.EmbarqueId = b.EmbarqueId
注意:此方案是直接用初始值扣除总和,和逐步递减的逻辑有差异——如果Percentage的计算依赖上一次更新后的结果,这个方案不适用。
关键提示
你之前的误区在于:SQL的UPDATE不会对同一行进行多次迭代更新,无论关联多少源数据,它都只会基于目标行的初始状态计算最终值。必须用循环或游标才能实现逐步更新的效果。
内容的提问来源于stack exchange,提问作者AhOkCasiCasiCasi
相关产品推荐
相关产品推荐

