代码之家  ›  专栏  ›  技术社区  ›  Chris Ballance

可以在使用SQL Server进行重复密钥更新时模拟MySQL功能

  •  9
  • Chris Ballance  · 技术社区  · 14 年前

    我正在使用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 回复  |  直到 14 年前
        1
  •  10
  •   Thomas    14 年前

    好吧,比尔打败了我们所有人,但这里有一个可能看起来像的例子:

    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)
    
        2
  •  8
  •   Bill Karwin    14 年前

    你应该阅读如何使用 MERGE Microsoft SQL Server 2008中的语句。这实际上是处理这种情况的ansi/iso sql方法(mysql的on duplicate key是一种专有的mysqlism)。

    参见文档 MERGE statement 在MSDN上。