可以使用SQL Server在DUPLICATE KEY UPDATE上模拟mySQL功能

时间:2010-07-26 22:47:55

标签: sql sql-server sql-server-2008 concurrency merge

我正在使用SQL Server 2008,并且希望能够利用mySQL的DUPLICATE KEY UPDATE语句的INSERT子句

当前遗留代码执行删除和后续插入,该插入遇到并发问题,并且来自不同线程的重复键插入:

以下是我在生产环境中看到的错误:

Violation of PRIMARY KEY constraint 'PK_Audience'. Cannot insert duplicate key in object 'dbo.Audience'.

(sp_ContentUpdate)

主键:

AudienceId, VersionId

违规SQL:

DELETE  FROM  dbo.Audience
WHERE   VersionId = @VersionId

IF  @AudienceXml IS NOT NULL
    BEGIN
    INSERT INTO dbo.Audience (
        VersionId,
        AudienceId,
        CreatedDate,
        CreatedByPersonId,
        )
    SELECT  @VersionId,
            AudienceId,
            GETUTCDATE(),
            @PersonId
                FROM    dbo.Audience
    JOIN    @AudienceXml.nodes('/Audiences/Audience') node(c)
    ON      Audience.AudienceName = c.value('@Name', 'nvarchar(50)')
    END

在事务中包装此TSQL似乎要么删除并发问题,要么通过更改时间来掩盖问题。但是,我不认为事务中的包装实际上已经解决了并发问题。

也许我正在犯这个错误。您的建议表示赞赏。

2 个答案:

答案 0 :(得分:10)

好吧,比尔击败了我们所有人,但这里有一个样子的样本:

Merge dbo.Audience As target
Using   (
        Select @VersionId As VersionId, AudienceId, GetUtcDate() As CreatedDate, @PersonId As CreatedByPersonId
        From dbo.Audience
            Join @AudienceXml.nodes('/Audiences/Audience') node(c)
                On Audience.AudienceName = c.value('@Name', 'nvarchar(50)')
        )
When Matched Then
    Update 
    Set VersoinId = target.VersionId, Audience = target.AudienceId
        , CreatedDate = target.CreatedDate
        , CreatedByPersionId = target.CreatedByPersonId
When Not Matched Then
    Insert dbo.Audience(VersionId, AudienceId, CreatedDate, CreatedByPersonId)

答案 1 :(得分:8)

您应该阅读有关如何在Microsoft SQL Server 2008中使用MERGE语句的信息。这实际上是ANSI / ISO SQL处理这种情况的方式(MySQL的ON DUPLICATE KEY是专有的MySQLism)。

请参阅MSDN上MERGE statement上的文档。