Я пытаюсь реализовать вашу базовую функциональность UPSERT, но с одной изюминкой: иногда я не хочу фактически обновлять существующую строку.
По сути, я пытаюсь синхронизировать некоторые данные между разными репозиториями, и функция Upsert мне показалась подходящей. Таким образом, во многом основано на ответе Сэма Шафрана на этот вопрос , а также некоторые другие исследования и чтения, я придумал эту хранимую процедуру:
(примечание: я использую MS SQL Server 2005, поэтому оператор MERGE не подходит)
CREATE PROCEDURE [dbo].[usp_UpsertItem]
-- Add the parameters for the stored procedure here
@pContentID varchar(30) = null,
@pTitle varchar(255) = null,
@pTeaser varchar(255) = null
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN TRANSACTION
UPDATE dbo.Item WITH (SERIALIZABLE)
SET Title = @pTitle,
Teaser = @pTeaser
WHERE ContentID = @pContentID
IF @@rowcount = 0
INSERT INTO dbo.Item (ContentID, Title, Teaser)
VALUES (@pContentID, @pTitle, @pTeaser)
COMMIT TRANSACTION
END
Мне это удобно для базового Upsert, но я бы хотел, чтобы фактическое обновление зависело от значения другого столбца. Думайте об этом как о «блокировке» строки, чтобы процедура Upsert не могла производить дальнейшие обновления. Я мог бы изменить оператор UPDATE так:
UPDATE dbo.Item WITH (SERIALIZABLE)
SET Title = @pTitle,
Teaser = @pTeaser
WHERE ContentID = @pContentID
AND RowLocked = false
Но тогда последующая вставка завершится ошибкой с нарушением уникального ограничения (для поля ContentID), когда она попытается вставить строку, которая уже существует, но не была обновлена, потому что она была «заблокирована».
Значит ли это, что у меня больше нет классического Upsert, т.е. что мне придется каждый раз выбирать строку, чтобы определять, можно ли ее обновить или вставить? Бьюсь об заклад, что это так, поэтому я предполагаю, что на самом деле я прошу помочь установить правильный уровень изоляции транзакции, чтобы процедура выполнялась безопасно.