更新whereselect,保证原子性

Update where select, guarantee atomicity

我有一个像这样的 T-SQL 查询:

UPDATE 
    [MyTable]
SET
    [MyField] = @myValue
WHERE
    [Id] = 
    (
        SELECT TOP(1) 
            [Id]
        FROM
            [MyTable]
        WHERE
            [MyField] IS NULL
            -- AND other conditions on [MyTable]
        ORDER BY
            [Id] ASC
    )

看来这个查询不是原子的(2个并发执行的select可以return同一个Id两次)

编辑: 如果我执行此查询,由 SELECT 编辑的 Id return 将无法用于下一次执行(因为 [MyField] 将不再为 NULL)。但是,如果我同时执行此查询两次,则两次执行可能 return 相同的 Id(第二次更新将覆盖第一次)。

我读过一个避免这种情况的解决方案是使用 SERIALIZABLE 隔离级别。这是最好/最快/最简单的方法吗?

先计算最大 ID,然后在交叉连接中使用它进行更新。

SQL DEMO

WITH cte as (
    SELECT TOP 1 ID
    FROM [MyTable]
    WHERE MYFIELD IS NULL
    ORDER BY ID
)
UPDATE t
SET [ID] = cte.[ID]
FROM [MyTable] t
CROSS JOIN  cte;

输出

这将产生前 1 个值,但如果它相同,您有可能 return 多个值。

尝试使用 DISTINCT

我知道 top(1) 应该只有 return 1 行,但问题表明它 return 不止一行。所以我认为这可能是因为价值相同。所以你可以使用这样的东西

    SELECT DISTINCT TOP 1 name FROM [Class];

它是那个或 where 子句来缩小结果

如我所见,UPDLOCK 就足够了(测试代码证实)