Я создал следующие образцы данных:
DROP TABLE IF EXISTS [dbo].[StackOverflow];
CREATE TABLE [dbo].[StackOverflow]
(
[ID] INT IDENTITY(1, 1) PRIMARY KEY
,[UserID] VARCHAR(12)
);
INSERT INTO [dbo].[StackOverflow]
VALUES (DEFAULT)
,(DEFAULT)
,(DEFAULT)
,(DEFAULT)
,(DEFAULT);
SELECT [ID]
,[UserID]
FROM [dbo].[StackOverflow];
Затем в двух отдельных окнах запросов я запустил следующий код:
BEGIN TRANSACTION;
WITH CTE AS
(
SELECT TOP 2 *
FROM [dbo].[StackOverflow]
WHERE [UserID] IS NULL
ORDER BY [ID]
)
UPDATE CTE
SET UserId = 1; -- in the second one change the `userid = 2`
--COMMIT TRANSACTION;
Итак, я имитирую два соединенияпытаясь выполнить обновления. Поскольку мы упорядочиваем по тем же критериям, мы видим, что второй запрос ожидает завершения первого запроса для правильной фильтрации данных.
SELECT [request_session_id]
,[resource_type]
,[resource_description]
,[resource_associated_entity_id]
,[request_mode]
,[request_type]
,[request_status]
FROM [sys].[dm_tran_locks]
WHERE [resource_database_id] = DB_ID()
ORDER BY [request_session_id]
,[resource_type];
Второй ожидает гранта для первой строки, поскольку он обновляется. Если мы передадим первый запрос, теперь вы увидите, что второй прочитал данные и предоставил блокировки другим строкам.
Теперь, ву нас есть таблица:
Таким образом, в таком случае вам не нужно беспокоиться о двух операторах, перезаписывающих данные.