sql >> Database >  >> RDS >> Sqlserver

Hoe een voorwaardelijke opgeslagen Upsert-procedure implementeren?

Ik heb het volgende script in elkaar geslagen om deze truc te bewijzen die ik in de afgelopen jaren heb gebruikt. Als u het gebruikt, moet u het aanpassen aan uw doeleinden. Reacties volgen:

/*
CREATE TABLE Item
 (
   Title      varchar(255)  not null
  ,Teaser     varchar(255)  not null
  ,ContentId  varchar(30)  not null
  ,RowLocked  bit  not null
)


UPDATE item
 set RowLocked = 1
 where ContentId = 'Test01'

*/


DECLARE
  @Check varchar(30)
 ,@pContentID varchar(30)
 ,@pTitle varchar(255)
 ,@pTeaser varchar(255)

set @pContentID = 'Test01'
set @pTitle     = 'TestingTitle'
set @pTeaser    = 'TestingTeasier'

set @check = null

UPDATE dbo.Item
 set
   @Check = ContentId
  ,Title  = @pTitle
  ,Teaser = @pTeaser
 where ContentID = @pContentID
  and RowLocked = 0

print isnull(@check, '<check is null>')

IF @Check is null
    INSERT dbo.Item (ContentID, Title, Teaser, RowLocked)
     values (@pContentID, @pTitle, @pTeaser, 0)

select * from Item

De truc hier is dat je waarden kunt instellen in lokale variabelen binnen een Update-statement. Hierboven wordt de "vlag"-waarde alleen ingesteld als de update werkt (dat wil zeggen, aan de updatecriteria wordt voldaan); anders wordt het niet gewijzigd (hier, links op null), u kunt dat controleren en dienovereenkomstig verwerken.

Wat betreft de transactie en het serialiseerbaar maken ervan, ik zou graag meer willen weten over wat er in de transactie moet worden ingekapseld voordat ik voorstel hoe verder te gaan.

-- Addenda, vervolg op tweede opmerking hieronder -----------

De ideeën van de heer Saffron zijn een grondige en solide manier om deze routine te implementeren, aangezien uw primaire sleutels buiten worden gedefinieerd en worden doorgegeven aan de database (d.w.z. u gebruikt geen identiteitskolommen - prima volgens mij, ze worden vaak te veel gebruikt).

Ik heb nog wat meer getest (een primaire sleutelbeperking toegevoegd aan kolom ContentId, de UPDATE en INSERT in een transactie verpakt, de serialiseerbare hint aan de update toegevoegd) en ja, dat zou alles moeten doen wat je wilt. De mislukte update slaat een bereikvergrendeling op dat deel van de index, en dat blokkeert alle gelijktijdige pogingen om die nieuwe waarde in de kolom in te voegen. Natuurlijk, als N verzoeken tegelijkertijd worden ingediend, zal de "eerste" de rij maken, en deze zal onmiddellijk worden bijgewerkt door de tweede, derde, enz. - tenzij u het "slot" ergens langs de regel instelt. Goede truc!

(Merk op dat zonder de index op de sleutelkolom, u de hele tabel zou vergrendelen. Ook kan de bereikvergrendeling de rijen aan "beide zijden" van de nieuwe waarde vergrendelen - of misschien niet, ik niet test die uit. Zou niet uit moeten maken, aangezien de duur van de bewerking [?] in milliseconden van één cijfer moet zijn.)



  1. Kan MySql 5.0 een weergave hebben van een tabel op een andere server?

  2. Bulksgewijs invoegen van generieke lijst C# in SQL Server

  3. Voor en na trigger op dezelfde gebeurtenis? Vul een onderliggende tabel PostgreSQL

  4. Illegale mix van sorteerfouten van MySql tijdens het uitvoeren van een testsuite voor rails