我正在尝试实现您的基本 UPSERT 功能,但有一个转折:有时我不想实际更新现有行。
本质上,我正在尝试在不同的存储库之间同步一些数据,而 Upsert 函数似乎是要走的路。因此,主要基于Sam Saffron 对这个问题的回答,以及其他一些研究和阅读,我想出了这个存储过程:
(注意:我使用的是 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,即我必须每次都选择行以确定它是否可以更新或插入?我敢打赌就是这样,所以我想我真正需要的是帮助正确处理事务隔离级别,以便程序安全执行。