2017-09-18 45 views
0

我有一个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个并发执行可以返回相同的ID两次)。

编辑: 如果我执行这个查询,SELECT返回的Id将不能用于下一次执行(因为[MyField]不会再为NULL)。但是,如果我同时执行两次这个查询,两次执行都会返回相同的ID(第二个UPDATE会覆盖第一个)。

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

+0

你是什么意思似乎?这应该只返回一个值。除非你使用'WITH TIES'选项。 –

+0

'select可以返回相同的ID两次'。嗯,它可能会总是返回相同的ID。 – sagi

+0

@sagi如果更新没有被执行。 – krimog

回答

2

正如我所看到的,UPDLOCK就足够了(测试代码确认)

0

计算最大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; 

输出

enter image description here

+0

检查编辑。使用交叉连接 –

+1

我不相信他想更新ID列。 –

+0

@DerrickMoeller是的,我意识到完成查询后。这就是为什么我要求样本数据和预期产出。但是这个想法就在那里。 –

0

这将导致顶部1值,但如果同样的,你必须返回多个值的潜力。

尝试使用DISTINCT

据我所知,顶(1)应仅返回1行,但该问题时其返回不止一行。所以我认为这可能是因为价值是一样的。所以,你可能使用类似这样

SELECT DISTINCT TOP 1 name FROM [Class]; 

它要么或where子句来缩小结果

+0

TOP 1将只返回一行。 –

+0

我以为它只是返回顶部行?那么如果这一行是相同的呢? –

+0

如果行是一样的?我不理解你的观点,DISTINCT将返回多个值。这似乎不是他的意图。 –