SQL更新top1行查询

Tin*_*ina 31 sql sql-server sql-server-2008

以下查询正在运行:

update  top(1) ShipBillInfo 
set     shipfirstname='kkk' 
where   CustomerId='134';
Run Code Online (Sandbox Code Playgroud)

但如果我尝试按某些Id订购,则显示错误:例如:

update  top(1) ShipBillInfo 
set     shipfirstname='kkk' 
where   CustomerId='134' 
order by 
        OredrGUID desc;
Run Code Online (Sandbox Code Playgroud)

Rem*_*anu 32

With cte as (
select  top(1) shipfirtsname  
From ShipBillInfo 
where   CustomerId='134' 
order by  OredrGUID desc)
Update cte set shipfirstname='abc';
Run Code Online (Sandbox Code Playgroud)

  • @ErikE:*在更新锁定之前发生其他行的读取*:否.阅读本身是否采取U锁定.这就是我所说的'CTE是UPDATE的目标'.扫描(或搜索)将获得U锁. (3认同)
  • @ErikE:*我可能会不必要地警告*如果您认为发生的情况(使用S锁或甚至nolock进行扫描,然后更新)将会发生警告将非常有必要.如果感兴趣的行将在连接或子查询中获取,那么你提到的问题*会发生,并且锁定提示是必要的.但由于更新直接针对CTE,因此引擎知道它必须做什么. (3认同)
  • @RemusRusanu我不确定是否会更改任何内容。查询会随着时间的推移而执行,并具有锁获取生命周期,当所选的行依赖于其他行的数据时(如ORDER BY一样),会出现并发问题。其他行的读取发生在更新锁之前,因此并发是一个问题。如果此特定查询由两个客户端同时执行,则不会有有害的副作用,因此我可能不必要地发出警告-我只是看到了该查询模式重用的潜在问题,并予以注意。 (2认同)

sto*_*ter 22

你为什么不这样做:

update ShipBillInfo 
set shipfirstname='kkk' 
where OrderGUID = (select top (1) OrderGUID  
                   from ShipBillInfo 
                   where CustomerId = 134 
                   order by OredrGUID desc )
Run Code Online (Sandbox Code Playgroud)


fab*_*tto 7

线程安全

对于线程安全解决方案,所提出的解决方案都不适用于我(某些行在同时执行时不止一次更新).

这有效:

UPDATE Account 
SET    sg_status = 'A'
WHERE  AccountId = 
(
    SELECT TOP 1 AccountId 
    FROM Account WITH (UPDLOCK) --this makes it thread safe
    ORDER  BY CreationDate 
)
Run Code Online (Sandbox Code Playgroud)

如果要返回更新项的某些列,可以将其放在更新语句中:( OUTPUT INSERTED.AccountIdSET和之间WHERE)

  • @StephanRyer,因为死锁是由 2 个或更多进程以不同的顺序锁定相同的资源引起的 - 为了避免死锁,您可以遵循 DDD 将资源分组为聚合的建议并锁定(用于更新)相同的资源(“根”资源)在涉及该组的所有事务中首先是聚合的 - 通过这种方式,行上的锁实际上可以提高情况的并发性 (2认同)