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

Chr*_*nce 9 sql sql-server concurrency merge sql-server-2008

我正在使用SQL Server 2008,并希望能够利用类似mySQL的ON DUPLICATE KEY UPDATE子句来进行INSERT语句

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

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

Violation of PRIMARY KEY constraint 'PK_Audience'. Cannot insert duplicate key in object 'dbo.Audience'.
Run Code Online (Sandbox Code Playgroud)

(sp_ContentUpdate)

首要的关键:

AudienceId, VersionId
Run Code Online (Sandbox Code Playgroud)

违反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
Run Code Online (Sandbox Code Playgroud)

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

也许我错了.您的建议表示赞赏.

Tho*_*mas 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)
Run Code Online (Sandbox Code Playgroud)


Bil*_*win 8

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

请参阅MSDN MERGE声明中的文档.