sql >> Databasteknik >  >> RDS >> Sqlserver

Hur implementerar man en villkorad lagrad Upsert-procedur?

Jag slog ihop följande manus för att bevisa detta trick som jag använde tidigare. Om du använder den måste du modifiera den för att passa dina syften. Kommentarer följer:

/*
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 här är att du kan ställa in värden i lokala variabler i en Update-sats. Ovan ställs "flagga"-värdet bara in om uppdateringen fungerar (det vill säga uppdateringskriterierna är uppfyllda); annars kommer det inte att ändras (här, vänster vid null), du kan kontrollera det och bearbeta därefter.

När det gäller transaktionen och att göra den serialiserbar, skulle jag vilja veta mer om vad som måste kapslas in i transaktionen innan jag föreslår hur man går vidare.

-- Tillägg, uppföljning från den andra kommentaren nedan -----------

Mr. Saffrons idéer är ett grundligt och solidt sätt att implementera denna rutin eftersom dina primära nycklar definieras utanför och skickas in i databasen (dvs. du använder inte identitetskolumner - bra av mig, de är ofta överanvända).

Jag gjorde några fler tester (lägg till en primärnyckelrestriktion på kolumn ContentId, slå in UPDATEN och INFOGA i en transaktion, lägg till den serialiserbara tipsen till uppdateringen) och ja, det borde göra allt du vill. Den misslyckade uppdateringen slår ett intervalllås på den delen av indexet, och det kommer att blockera alla samtidiga försök att infoga det nya värdet i kolumnen. Naturligtvis, om N förfrågningar skickas samtidigt, kommer den "första" att skapa raden, och den kommer omedelbart att uppdateras av den andra, tredje, etc. - om du inte ställer in "låset" någonstans längs linjen. Bra knep!

(Observera att utan indexet i nyckelkolumnen skulle du låsa hela tabellen. Dessutom kan intervalllåset låsa raderna på "vardera sidan" av det nya värdet - eller så kanske de inte gör det, det gjorde jag inte testa den. Det borde inte spela någon roll, eftersom operationens varaktighet bör [?] vara i ensiffriga millisekunder.)



  1. Kan SQLExpress 2005 och 2008 installeras på samma maskin utan problem?

  2. Hur man installerar WordPress:Serverprogramvaran

  3. Bygga en mycket tillgänglig databas för Moodle med MariaDB (replikering och MariaDB-kluster)

  4. NodeJS Hur man hanterar samtidig förfrågan till MySQL