2010-07-26 10 views
9

Sto usando SQL Server 2008, e vorrei essere in grado di approfittare di qualcosa come ON DUPLICATE KEY UPDATE clausola di MySQL per INSERT dichiarazionipossibile simulare la funzionalità di MySQL su DUPLICATE KEY UPDATE con SQL Server

codice legacy Current fa una cancellazione e la successiva inserto che esegue in problemi di concorrenza con inserti chiave duplicate da thread separati:

Qui è l'errore che vedo nel mio ambiente di produzione:

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

(sp_ContentUpdate)

Chiave primaria:

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 

Wrapping questo TSQL in una transazione sembra rimuovere il problema di concorrenza o di mascherare il problema modificando i tempi. Tuttavia, non penso che il wrapping in una transazione abbia effettivamente risolto la concorrenza.

Forse mi sto sbagliando. I tuoi suggerimenti sono apprezzati.

+0

possibile duplicato del [non SQL Server offrono nulla di simile ON DUPLICATE KEY UPDATE di MySQL] (http: // StackOverflow .com/questions/1197733/does-sql-server-offer-anything-like-mysqls-on-duplicate-key-update) –

risposta

10

Bene, Bill ci ha battuto tutti, ma qui è un esempio di quello che potrebbe essere simile:

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 Cheers per l'esempio, Thomas. –

+0

+1 Wow, grazie per aver fatto il lavoro. –

+1

@Bill Karwin - Thx. Quando hai risposto, mi sentivo come il personaggio di Rusty quando cerca di reclutare Saul nell'Oceano 11. "Thomas, ho visto la risposta prima di alzarti stamattina." Ma anche i punti brownie per un po 'di lavoro extra sono belli. :) – Thomas

8

Si dovrebbe leggere su come usare l'istruzione MERGE in Microsoft SQL Server 2008. Questo è in realtà il modo ANSI/ISO SQL di gestire questa situazione (il DUPLICATE KEY di MySQL è un MySQLism proprietario).

Vedere i documenti su MERGE statement su MSDN.

+1

+1: Drats, bastonatemi. –

Problemi correlati