2010-07-26 3 views
9

J'utilise SQL Server 2008, et souhaite être en mesure de tirer profit de quelque chose comme clause ON DUPLICATE KEY UPDATE de mySQL pour INSERT déclarationspossible de simuler la fonctionnalité mySQL ON DUPLICATE KEY UPDATE avec SQL Server

code existant actuel ne une suppression et insertion ultérieure qui est en cours d'exécution dans les problèmes de concurrence avec double inserts clés de fils séparés:

Voici l'erreur que je vois dans mon environnement de production:

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

(sp_ContentUpdate)

clé primaire:

AudienceId, VersionId 

Offending 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 

Emballage ce TSQL dans une transaction semble soit supprimer la question de la concurrence ou de masquer le problème en changeant les timings. Cependant, je ne pense pas que l'encapsulation dans une transaction ait réellement résolu la concurrence.

Peut-être que j'y vais mal. Vos suggestions sont appréciées.

+0

double possible (http [Tout comme Duplicate KEY UPDATE MySQL offre ne SQL Server]: // stackoverflow .com/questions/1197733/ne-sql-serveur-offre-rien-comme-mysqls-sur-duplicate-clé-mise à jour) –

Répondre

10

Eh bien, Bill nous a tous battus, mais voici un échantillon de ce qu'il pourrait ressembler à:

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

+1 Bravo pour l'exemple, Thomas. –

+0

+1 Wow, merci de faire le travail. –

+1

@Bill Karwin - Thx. Quand tu as répondu, je me sentais comme le personnage de Rusty quand il essayait de recruter Saul dans Ocean 11. "Thomas, j'ai vu la réponse avant que tu te lèves ce matin." Mais, les points brownie pour un peu de travail supplémentaire est bien aussi. :) – Thomas

8

Vous devriez lire sur la façon d'utiliser l'instruction MERGE dans Microsoft SQL Server 2008. Ceci est en fait la norme ANSI/ISO SQL façon de gérer cette situation (Duplicate KEY de MySQL est un MySQLism propriétaire).

Voir documentation sur le MERGE statement sur MSDN.

+1

+1: Drats, me battre à elle. –

Questions connexes