sql >> Database teknologi >  >> RDS >> Sqlserver

Hvordan implementerer man en betinget Upsert-lagret procedure?

Jeg slog følgende script sammen for at bevise dette trick, jeg brugte i år tidligere. Hvis du bruger det, skal du ændre det, så det passer til dine formål. Kommentarer følger:

/*
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

Tricket her er, at du kan indstille værdier i lokale variabler i en Update-sætning. Ovenfor indstilles "flag"-værdien kun, hvis opdateringen virker (det vil sige, at opdateringskriterierne er opfyldt); ellers bliver det ikke ændret (her venstre ved null), du kan tjekke for det og behandle i overensstemmelse hermed.

Hvad angår transaktionen og gør den serialiserbar, vil jeg gerne vide mere om, hvad der skal indkapsles i transaktionen, før jeg foreslår, hvordan man fortsætter.

-- Tilføjelser, opfølgning fra anden kommentar nedenfor -----------

Mr. Saffrons ideer er en grundig og solid måde at implementere denne rutine på, da dine primære nøgler er defineret udenfor og sendt ind i databasen (dvs. du bruger ikke identitetskolonner - fint af mig, de er ofte overbrugte).

Jeg foretog nogle flere tests (tilføjede en primær nøglebegrænsning på kolonne ContentId, pakke OPDATERING og INDSÆT i en transaktion, føj det serialiserbare hint til opdateringen) og ja, det burde gøre alt, hvad du vil have det til. Den mislykkede opdatering slår en intervallås på den del af indekset, og det vil blokere ethvert samtidig forsøg på at indsætte den nye værdi i kolonnen. Selvfølgelig, hvis N anmodninger indsendes samtidigt, vil den "første" skabe rækken, og den vil straks blive opdateret af den anden, tredje osv. - medmindre du indstiller "låsen" et sted langs linjen. Godt trick!

(Bemærk, at uden indekset på nøglekolonnen, ville du låse hele tabellen. Desuden kan områdelåsen låse rækkerne på "enhver side" af den nye værdi - eller måske vil de ikke, det gjorde jeg ikke test den. Det burde ikke betyde noget, da varigheden af ​​operationen skal [?] være i etcifrede millisekunder.)



  1. Sådan opretter du en databasemodel fra bunden

  2. Oprettelse af et indeks på et tidsstempel for at optimere forespørgslen

  3. at vælge et specifikt tal som kolonneværdi i forespørgslen

  4. Hvordan relaterer jeg en tabel til mange forskellige tabeller?