Vad är triggers i sql. Funktioner hos industriella servrar. En underbart enkel trigger: loggning och revision

  1. Utforska vilka typer av triggers som kan skapas på MS-servern SQL Server 2000.
  2. Studera operatörerna för att beskriva utlösare av olika typer och de restriktioner som åläggs giltiga operatörer inuti avtryckarkroppen.
  3. Lär dig hur du skapar och felsöker utlösare på MS SQL Server 2000.
  4. Utveckla fem triggers för träningsdatabasen "Bibliotek", som din lärare föreslår från de uppgifter som beskrivs i arbetet.
  5. Utarbeta en rapport om utfört arbete i elektronisk form.

1. Skapa en utlösare

Utlösare det här är metoder med vilka en applikationsutvecklare för MS SQL Server kan säkerställa databasens integritet. Detta är en typ av lagrad procedur som anropas när ett försök görs att ändra data i en tabell för vilken en utlösare är definierad. SQL Server utför denna procedur under infogning, uppdatering och borttagning (INSERT, UPDATE, DELETE) på en given tabell. Eftersom utlösaren används efter att operationen har slutförts, representerar den det sista ordet i modifieringen. Om en utlösare orsakar ett fel i en fråga, vägrar SQL Server att uppdatera informationen och returnerar ett felmeddelande till applikationen som utför åtgärden. Om en utlösare är definierad för en tabell kan den inte förbigås när motsvarande operation utförs.

Även om en utlösare är en typ av lagrad procedur kan den inte anropas direkt: den svarar bara på de händelser som den är definierad för.

I MS SQL SERVER 2000 dök upp den nya sorten trigger I STÄLLET FÖR -trigger. Hans grundläggande skillnad från vanliga (AFTER) triggers är att den exekveras inte efter infogning, ändring eller borttagning, utan istället för den.

Mest allmän användning utlösa stöd för integritet i databaser.

Triggers har en mindre inverkan på serverns prestanda och används ofta för att förbättra satser som utför flerstegsoperationer på tabeller och rader.

För att skapa en utlösare måste du vara ägare till tabellen som utlösaren skapas för, eller vara medlem i rollen db_ägare eller db_ddladmin, eller vara administratör för en SQL-server, det vill säga vara medlem i en fast serverroll sysadmins. När du lägger till en utlösare till en tabell ändras åtkomsttypen, förhållandet mellan andra objekt till den osv.

Att skapa en utlösare liknar att deklarera en lagrad procedur och har följande syntax:

SKAPA TRIGGER trigger_name
På bord
{
(FÖR | EFTER | I STÄLLET FÖR) ( [,] [,] )

SOM
(OM UPPDATERING(kolumn_i)
[(OCH | ELLER) UPPDATERING (kolumn_j)]
[... n]
| IF (COLUMNS_UPDATED() (bit_operator) bit_mask)
(jämförelseoperatör) kolumnbitmask [… n]
}
SQL-satser [... n]
}
}

  • trigger_name måste följa vanliga SQL Server-objektnamnkonventioner och vara unikt i databasen;
  • tabellnamnet på tabellen för vilken utlösaren skapas;
  • MED KRYPTERING Det här alternativet ger utvecklare möjligheten att förhindra användare från att läsa triggertexten efter att den har laddats upp till servern. Återigen, notera att för att göra triggertexten verkligen omöjlig att återställa, bör du ta bort motsvarande rader från syscomments-tabellen efter kryptering;
  • FÖR DELETE , INSERT , UPDATE nyckelord som definierar tabellmodifieringsoperationen, vid exekvering av vilken triggern kommer att aktiveras;
  • MED BILAGA detta alternativ krävs endast om ställ in nivån kompatibiliteten överstiger inte 65 och används för att skapa ytterligare triggers;
  • NOT FOR REPICATION indikerar att triggern inte är aktiverad när en tabell modifieras under replikering;
  • AS-nyckelord som anger början av triggerdefinitionen;
  • SQL_statements I T-SQL kan en trigger innehålla valfritt antal SQL-satser så länge de är omgivna av operatorparenteser BEGIN ... END ;
  • IF UPDATE (kolumn) för att lägga till och uppdatera dataoperationer, kan du definiera ytterligare villkor till en specifik tabellkolumn; när du anger flera kolumner separeras de logiska operatorer;
  • IF (COLUMNS_UPDATED()) Vi visade ovan hur du kan använda IF UPDATE (kolumn)-konstruktionen för att avgöra vilka kolumner som påverkas av ändringar. Om du behöver kontrollera om en specifik kolumn ändras är den här konstruktionen mycket bekväm. Dock när man bygger svåra förhållanden, som innehåller många kolumner, är denna design för besvärlig. IF (COLUMNS_UPDATED())-konstruktionen är avsedd för sådana fall. Resultatet av funktionen COLUMNS_UPDATED() är en uppsättning bitar, som var och en motsvarar en tabellkolumn; Den minst signifikanta biten motsvarar den första kolumnen, den mest signifikanta biten motsvarar den sista. Om operationen som fick utlösaren att aktiveras försökte ändra en viss kolumn, kommer motsvarande bit att sättas till 1;
  • bit_operator bitvis operatör som definierar allokeringsoperationen nödvändiga bitar, erhållen med COLUMNS_UPDATED() . Vanligtvis används operatorn &;
  • bit_mask i kombination med den bitvisa operatorn låter bitmasken dig markera de bitar som är av intresse för utvecklaren, det vill säga avgöra om kolumnerna av intresse ändrades i operationen som fick utlösaren att aktiveras;
  • comparison_operator Och kolumn_bitmask funktionen COLUMNS_UPDATED() ger en uppsättning bitar motsvarande föränderliga kolumner. Med hjälp av en bitmask och en bitvis operator utförs en transformation på denna uppsättning bitar och en viss mellanresultat. Jämförelseoperatorn jämför detta mellanresultat med kolumnens bitmask. Om resultatet av jämförelsen är sant, kommer uppsättningen SQL-satser som utgör kroppen av utlösaren att exekveras, annars kommer den inte att göras.

Låt tabellen ha följande struktur:

SKAPA tabell mytable (a int, b int, c int, d int, e int)

Fem kolumner motsvarar fem bitar, varav den minst signifikanta motsvarar kolumn a, den mest signifikanta motsvarar kolumn e. Låt operationen som aktiverar utlösaren ändra kolumnerna a, b och e. Då kommer funktionen columns_updated att ge värdet 10011. Låt oss inte vara intresserade av att ändra kolumner b och d, utan vi är intresserade av att ändra alla andra kolumner (a, c och e), det vill säga masken blir 10101. Kom ihåg att i skrivande stund vet vi inte vilka kolumner som kommer att påverkas av den eller den modifierings- eller infogningsoperationen, det vill säga vilket resultat funktionen columns_updated kommer att ge. Genom att specificera den bitvisa jämförelseoperatorn vid körning får vi 10011 & 10101, vilket resulterar i 10001, vilket i decimalnotation är 17. Att jämföra detta värde med jämförelseoperatorn och kolumnbitmasken kommer att tala om för oss om ändrings-/infogningsoperationen uppfyller kraven betingelser. Så, till exempel, om affärslogik kräver att utlösaren utlöses när alla kolumner vi är intresserade av ändras (a, c, e), då, naturligtvis, parametrarna bitmask och kolumn_bitmask måste ha samma värden, och jämförelseoperatorn måste vara ett likhetstecken. Således, för vårt exempel, kommer hela strukturen att se ut så här:

OM(kolumner_uppdaterad & 17) = 17

Om det krävs att minst en av kolumnerna vi är intresserade av ändras så blir konstruktionen följande:

IF (columns_updated & 17) > 0

Med hjälp av bitoperationer kan du uppnå stor flexibilitet i att komponera sådana konstruktioner.

Du kan också skapa triggers med SQL Server Enterprise Manager.

  1. Starta SQL Server Enterprise Manager.
  2. Högerklicka på tabellen som du vill skapa en utlösare för och välj Uppgift > Hantera utlösare från snabbmenyn. Som ett resultat av dessa åtgärder kommer en dialogruta att visas där du kan skriva in triggertexten och ge den ett namn.
  3. När du har slutfört din inmatning kan du kontrollera syntaxen och klicka på OK för att spara utlösaren i databasen.

Begränsningar när du skapar triggers

  • CREATE TRIGGER-satsen kan bara användas på en tabell.
  • En trigger kan bara skapas i nuvarande bas data, men det kan hänvisa till externa objekt.
  • I ett uttalande för att skapa utlösare kan du ange flera åtgärder som den kommer att reagera på.
  • Kan inte användas i triggertext följande instruktioner: ÄNDRA DATABAS, ÄNDRA PROCEDUR, ÄNDRA TABELL, SKAPA STANDARD, SKAPA PROCEDUR, ÄNDRA TRIGGER, ÄNDRA VISNING, SKAPA DATABAS, SKAPA REGEL, SKAPA SCHEMA, SKAPA TRIGGER, SKAPA VISNING, SKAPA INIT, DISK ÄNDRA STORLEK, DROPPA, DROPPA, SLIPPROCEDUR, SLAPPREGEL, SLIP TRIGGER, SLAPPVISNING, RESOTRE DATABAS, ÅTERSTÄLLNINGSLOGG, ÅTERKONFIGURERA, UPPDATERA STATISTIK.
  • Alla giltiga SET-operationer fungerar bara när avtryckaren är aktiv.
  • Du kan inte köra en utlösare som undersöker tillståndet för ett binärt stort objekt (BLOB) av datatypstext eller bild i tabellkolumnerna INSERTED och DELETED, oavsett om proceduren loggas eller inte.
  • Bör inte användas SELECT-satser, returnerar resultatuppsättningar från en utlösare, för en klientapplikation som kräver specialavdelning resultatuppsättningar, oavsett om detta görs i en lagrad procedur eller inte.
  • Du kan inte skapa utlösare INSTAAD OF UPDATE och DELETE på tabeller som har främmande nycklar med installerade tillval kaskad ändra eller ta bort, respektive.

2. Exempel på användning av triggers

Exempel 1: Infoga och uppdatera utlösare

Dessa triggers är bekväma eftersom de kan stödja förhållanden referensintegritet och se till att data är korrekta innan de skrivs in i ett kalkylblad. Triggers används vanligtvis för att uppdatera tidskolumner eller för att kontrollera data i specifika kolumner mot ett obligatoriskt kriterium. Triggers bör användas när testkriteriet är mer komplext än det deklarativa integritetsvillkoret.

I exemplet nedan körs utlösaren när en rad infogas eller ändras i försäljningstabellen. Om beställningsdatumet inte ligger inom de första 15 dagarna i månaden läggs inte raden in i tabellen.

SKAPA TRIGGER Tri_Ins_Sales
På rea
FÖR INFOGA, UPPDATERA
SOM
/* Deklarera nödvändiga lokala variabler */
FÖRKLARA @nDayOfMonth TINYINT
/* Hitta information om den tillagda posten */
SELECT @nDayOfMonth = DatePart(day, i.ord_date)
FRÅN Försäljning, infogat i
WHERE s.stor_id = i.stor_id
OCH s.ord_num = i.ord_num
OCH s.title_id = i.title_id
/* Kontrollera felkriteriet och, om nödvändigt,
skicka felmeddelande */
OM @nDayOfMonth > 15
BÖRJA
/* Obs: Återställ alltid först. Du kanske inte vet
vilken typ av bearbetningsfel som kan orsaka
omotiverat länge sedan låser */
ROLLBACK TRAN
RAISERROR("Endast beställningar som lämnats på den första
15 dagar i månaden", 16, 10)
SLUTET

Om vi ​​nu försöker infoga eller uppdatera en post i tabellen, om det angivna villkoret inte är uppfyllt, får vi ett motsvarande felmeddelande.

Observera att kodavsnittet kommer åt en ny tabell, och den här tabellen finns inte i listan över databastabeller. I I detta fall tabellen Infogad innehåller en kopia av varje rad, som endast kommer att läggas till om transaktionen slutförs framgångsrikt. Denna tabell och dess värden används när du utför en jämförelseoperation för att verifiera transaktionens giltighet.

Kolumnerna för infogade tabeller är exakt samma som kolumnerna i kalkylbladet. Jämförelsen kan göras med kolumner, som i i detta exempel, där kolumnerna i tabellen Försäljning jämförs för att kontrollera att försäljningsdatumen är korrekta.

Du kan också skapa triggers som bara utför arbete när en specifik kolumn uppdateras. För att avgöra om bearbetningen ska fortsätta i en utlösare kan IF UPDATE-satsen användas:

OM UPPDATERING(au_lname)
OCH (@@ROWCOUNT=1)
BÖRJA
…
SLUTET

Koden inuti blocket exekveras endast om kolumnen au_lname uppdateras. Kom alltid ihåg att kolumnen som uppdateras inte ändras i alla fall. Om några ändringar är nödvändiga, många applikationer, inklusive de flesta företagssystem, uppdatera bara hela raden.

UPDATE-operationen påverkar båda systemtabellerna. Tabellen Infogade lagrar nya värden, och tabellen Borttaget lagrar gamla värden. Därför kan du använda båda dessa tabeller när du analyserar förändringar.

Det är ofta nödvändigt att ersätta vissa värden med odefinierade värden. Detta görs med en enkel tilldelningsoperation, till exempel:

NUM_READER = NULL

Exempel 2: Ta bort utlösare

Ta bort triggers ( ta bort triggers) används vanligtvis i två fall: förhindrar radering av rader som kan orsaka dataintegritetsproblem, till exempel en rad som används som en främmande nyckel till andra tabeller, och utför kaskadraderingsoperationer på underordnade ( barn) huvudlinjer ( bemästra) linjer. Denna trigger kan användas för att ta bort all orderinformation från huvudlinjen försäljning

Triggers tar hänsyn till totala summan alla rader som påverkas av den begärda åtgärden. Så de borde kunna jobba med olika kombinationer informationen i tabellen och returnera nödvändiga uppgifter. Till exempel, när en DELETE FROM Authors-sats körs, måste utlösaren beakta att satsen kommer att ta bort alla rader från tabellen.

I följande exempel förhindrar användning av variabeln @@ROWCOUNT att mer än en rad tas bort. Den här utlösaren körs när en användare försöker ta bort en rad från tabellen Stores. Om informationen är relaterad till försäljning, förhindrar utlösaren att begäran slutförs.

SKAPA TRIGGER Tri_Del_Stores
ON butiker
FÖR DELETE
SOM
/* Kontrollera antalet modifierade rader och förbjud borttagning av mer än en rad åt gången */
OM @@ RADANTAL > 1
BÖRJA
ROLLBACK TRAN
RAISERROR ("Endast en rad kan tas bort åt gången.", 16, 10)
SLUTET
/* Deklaration av en temporär variabel för att spara förstörd information */
DECLARE @ StorID char (4)
/* Hämta värdet på raden som ska raderas */
VÄLJ @StorID = d.stor_id
FRÅN butiker, raderade d
VAR s.stor_id *= d.stor_id
OM FINNS (VÄLJ *
FRÅN Försäljning
WHERE stor_id = @storID)
BÖRJA
ROLLBACK TRAN
RAISERROR ("Denna information kan inte raderas eftersom det finns en motsvarande post i försäljningstabellen.", 16, 10)
SLUTET

Obs: Att använda RAISERROR är det enklaste sättet att skicka detaljerad och detaljerad information till den anropande processen eller användaren. specifik information om felet. RAISERROR gör det möjligt att specificera meddelandetext, risknivå, informationsstatus och kombinera allt detta för användaren till ett beskrivande meddelande. Denna instruktion gör det också lättare att skriva vanliga felhanteringsblock i klientapplikationer.

Det här exemplet använder också flera transaktionskontrollsatser för att stoppa operationer från att köras. Observera att kodavsnittet kommer åt en ny tabell. Den här tabellen finns inte i listan över databastabeller. I det här fallet innehåller tabellen Borttaget en kopia av varje rad, som endast kommer att läggas till om transaktionen slutförs framgångsrikt. Denna tabell och dess värden används när du utför en jämförelse för att verifiera transaktionens giltighet.

Kolumnerna i tabellen Borttaget är exakt samma som kolumnerna i kalkylbladet. Jämförelsen kan göras kolumn för kolumn, som visas i exemplet där kolumnerna i tabellen Borttaget jämförs med kolumnerna i försäljningsdatabasen. Detta säkerställer att informationen som ska raderas inte inkluderar försäljningsdata.

Exempel 3. I STÄLLET FÖR triggers

I STÄLLET FÖR triggers skiljer sig från vanliga (EFTER) triggers genom att de utförs inte efter operationen som ledde till dess avfyrning, utan istället med alla efterföljande konsekvenser, till exempel, såsom möjligheten att använda dem i samband med integritetsbegränsningar. Systemtabellerna Insatta och Borttagna används i dem på samma sätt som i AFTER-utlösare. Avtryckarkroppen kan duplicera operationen som fick den att brinna, men detta krävs inte. Med andra ord, om vi definierar en INSTEAD OF DELETE-utlösare, så hindrar ingenting oss från att utföra en DELETE-operation på den, som tar bort alla rader som borde ha raderats i enlighet med operationen som kallade utlösaren, men vi har inte att göra detta.

Låt oss ge ett exempel på hur du använder triggern I STÄLLET FÖR.

Tabellen Jobb har en 1:M-relation med tabellen Anställda, så det är inte möjligt att ta bort ett jobb om det redan har anställda tilldelade det. Låt oss skapa en trigger som, när ett jobb raderas, kontrollerar om anställda tilldelas det eller inte. Om det tilldelas kommer arbetet inte att raderas. På grund av det faktum att det finns en integritetsbegränsning (DRI) kan AFTER-utlösaren inte fungera tillsammans med den. Det vill säga, du kan skapa en trigger så här:


FÖR DELETE
SOM
OM FINNS (VÄLJ * FRÅN Anställd e JOIN Raderad d PÅ e.job_id=d.job_id)
BÖRJA
ROLLBACK TRAN
SLUTET

Notera förresten att till skillnad från exempel 2 låter den här utlösaren dig ta bort flera rader samtidigt. En sådan trigger kan dock bara fungera korrekt om kopplingen mellan tabellerna Employees och Jobs bryts så att DRI:er inte bearbetas innan triggern exekveras.

Men du kan skapa en ISTADEN FÖR trigger:

SKAPA TRIGGER Check_Job ON jobb
I STÄLLET FÖR DELETE
SOM
DELETE FROM Jobs FROM Jobs j JOIN raderade d på d.job_id = j.job_id
WHERE j.job_id NOT IN (VÄLJ DISTINCT Job_id FROM Employee)

En sådan trigger kommer inte att ha konflikter med DRI och kommer att exekveras.

DRI-kontrollen utförs omedelbart efter utförandet av operationen, det vill säga före utförandet av AFTER-utlösaren. När du använder en INSTEAD OF flip-flop, utförs operationen i princip inte och kontrollen överförs till vippan, så DRI kommer inte att exekveras.

Som redan nämnts innehåller tabellen Infogade tillagda rader och tabellen Borttagna innehåller rader borttagna. Det är lätt att gissa att när du utför en uppdateringsoperation kommer både tabellen Infogad och raderad att användas. I det här fallet kommer de gamla värdena att hamna i tabellen Borttaget och de nya i tabellen Infogade. Genom att kombinera dem efter nyckelkolumner är det inte svårt att avgöra vilka värden som ändrades.

3. Använda kapslade utlösare

Triggers kan bäddas in i varandra. 32 nivåer av häckning är tillåtna. Om kapslade triggeroperationer inte önskas kan SQL Server konfigureras för att inaktivera dem.

Obs: Kapslingsnivån för en utlösare kan kontrolleras när som helst genom att polla värdet som ställts in i @@NESTLEVEL-variabeln. Det bör vara i intervallet från 0 till 32.

Kapslade triggers kan leda till rekursion. Det finns två typer av rekursion: direkt och indirekt. Direkt rekursion uppstår om avfyrningen av en trigger leder till förändringar som orsakar samma trigger igen. Indirekt rekursion uppstår när avfyrningen av en avtryckare orsakar förändringar som gör att en annan avtryckare avfyras, vilket i sin tur leder till förändringar som gör att den första avtryckaren avfyras. Naturligtvis kan denna kedja också bestå av ett större antal triggers.

Direkt rekursion kan inaktiveras (och aktiveras) med hjälp av databasalternativet RECURSIVE_TRIGGERS. Du kan inaktivera (och aktivera) indirekt rekursion, såväl som kapsling av utlösare i allmänhet, med hjälp av serveralternativet för kapslade utlösare. Det här alternativet bestämmer möjligheten att kapsla utlösare inte för en specifik databas, utan för hela servern.

Det bör noteras att I STÄLLET FÖR triggers till sin natur inte är föremål för direkt rekursion.

När du skapar en utlösare kan SQL Server inte på egen hand känna igen att någon kapslad konstruktion orsakar oändlig cykel. Ett sådant faktum kan endast fastställas under exekveringen av denna trigger.

Låt oss anta att Tabell_A inkluderar en trigger, trigger_A , som körs när en uppdatering av Tabell_A sker. När trigger_a körs får Table_B att uppdateras. Den här tabellen innehåller en trigger_b som körs när Tabell_B uppdateras och gör att Tabell_A uppdateras. Således, om användaren uppdaterar någon av dessa två tabeller, fortsätter de två triggerna att få varandra att köra på obestämd tid. När den här situationen inträffar stänger SQL Server eller avbryter exekvering av triggern.

Låt oss föreställa oss att tabellen Försäljning innehåller en utlösare och tabellen Butiker innehåller en annan. Följande visar definitionen av två kapslade utlösare som exekveras när en raderingsåtgärd sker i tabellen Försäljning:

/* Den första utlösaren förstör rader i Stores-tabellen,
om rader i försäljningstabellen förstörs */
SKAPA TRIGGER Tri_Del_Sales
På rea
FÖR DELETE
SOM

SKRIV UT "En raderingsutlösare körs för försäljningstabellen..."
/* Deklaration av en temporär variabel för att lagra raderad information */
DECLARE @sStorID char(4),@sMsg varchar(40)
/* Hämta ID-värdet för raden som ska raderas */

FRÅN Raderad


/* Ta bort en rad */
SELECT @sMsg = "Butik " + @sStorID + " raderad"
SKRIV UT @sMsg
DELETE FRÅN Butiker
WHERE stor_id = @sStorID
SKRIV UT "Slut på triggerkörning för försäljningstabell"

/* Den andra utlösaren förstör rader i en tabell,
om raderna i en annan förstörs */

ON butiker
FÖR DELETE
SOM
/* Deklaration av utlösaren som ska exekveras */
SKRIV UT "En borttagningsutlösare körs för tabellen Butiker..."
/* Deklaration av en temporär variabel för informationslagring,
förstörd från bordet */
DECLARE @sStorID char(4), @sMsg varchar (200)
/* Få det förstörda värdet */
VÄLJ TOP 1 @sStorID = stor_id
FRÅN Raderad
/* Raderad är en hjälptabell som SQL Server
används för att lagra förstörda poster */
OM @@ROWCOUNT = 0
BÖRJA
SKRIV UT "Det finns inga matchande rader i tabellen Butiker"
LÄMNA TILLBAKA
SLUTET
/* Ta bort en post */
SELECT @sMsg = "Ta bort butiksspecifika rabatter" + @sStorID
SKRIV UT @sMsg
TA BORT rabatter
WHERE Stor_id = @sStorID
SKRIV UT "Antal rabatter borttagna: " + CONVERT(VARCHAR(4), @@ROWCOUNT)
SKRIV UT "Slut på exekvering av trigger för butikstabell"

Om en DELETE-sats körs på försäljningstabellen, som visas i följande exempel, aktiveras utlösaren, vilket i sin tur får utlösaren för butikstabellen att köras.

Låt oss göra:

DELETE FROM Sales WHERE stor_id = "8042"

Resultat:

En raderingsutlösare körs på försäljningstabellen...
Butik 8042 borttagen
En borttagningsutlösare körs i butikstabellen...
Ta bort rabatter relaterade till butik 8042
(1 rad(er) påverkas)
Antal borttagna rabatter: 1
Slut på triggerkörning för tabellen Stores
(1 rad(er) påverkas)
(4 rad(er) påverkas)
Slut på triggerkörning för försäljningstabell

Var uppmärksam på ordningen på meddelandena som visas. Först aktiveras avtryckaren på försäljningsbordet. Den tar bort en rad från Stores-tabellen och utlöser på så sätt en trigger på den. Dessutom, faktiskt, varken försäljningstabellen eller Stroes-tabellen har raderats ännu (radering pågår) detta bevisas av frånvaron automatiskt meddelande server (N rad(er) påverkade), som visas vid radering från valfri tabell och visar hur många rader som togs bort.

När den väl har lanserats tar utlösaren på tabellen Butiker bort relaterade rader från rabatttabellen (Rabatter), som visar meddelandet (1 rad(er) påverkas). Den skriver sedan ut lämpliga meddelanden och avslutar sitt arbete. Så snart den har avslutat sitt arbete raderas raden från Stores-tabellen, vars radering gjorde att den fungerade. Sedan, eftersom den här raden raderas, återgår utlösaren i tabellen Stores att fungera. Denna trigger ger ut sin senaste meddelandet om arbetets slut och slut. När det har slutförts visas meddelandet (1 rad(er) påverkas), vilket indikerar att en rad har tagits bort från tabellen Stores. Och först efter detta raderas slutligen raderna från försäljningstabellen.

Obs: Triggers och deklarativ referensintegritet kan i allmänhet inte fungera tillsammans. Till exempel, det föregående exemplet visar att innan du kör en DELETE-sats måste du först ta bort villkoret på FOREIGN KEY-värdet i tabellen Rabatter. Där det är möjligt bör antingen en utlösare eller ett referensintegritetsvillkor användas. Men, som redan nämnts, dök Istället för triggers upp i MS SQL Server 2000. De kan användas tillsammans med deklarativa integritetsmekanismer, men du kan inte använda kaskadoperationer i anslutningar för samma operation som INSTEAD OF-utlösaren skapades för. Till exempel, om en INSTEAD OF DELETE-utlösare skapas, kan du inte använda ON DELETE CASCADE-konstruktionen i relationer där denna tabell är en underordnad tabell.

Exempel 2

Låt oss nu ge ett exempel på direkt rekursion i triggers. Låt oss skapa en trigger som, när en anställd raderas, även skulle ta bort de anställda som har samma efternamn eller förnamn som den som raderas. Dessutom, när anställda raderas av en utlösare, utlöses samma utlösare igen för denna radering och återigen tar bort personer med samma efternamn eller förnamn, och så vidare.

SKAPA TRIGGER Del_Empl_Tr ON Anställd
FÖR DELETE
SOM
OM FINNS (VÄLJ * FRÅN Anställd e
JOIN Raderade d på e.lname = d.lname ELLER e.Fname = d.fname)
DELETE FRÅN anställd
FRÅN Anställd e JOIN Raderad d på e.lname = d.lname ELLER e.Fname = d.fname

Det finns inga anställda med samma efternamn eller förnamn i pubdatabasen, men du kan själv lägga till sådana anställda och kolla vad som händer om du tar bort någon av dem. Låt till exempel följande anställda vara i databasen:

Om du nu följer instruktionerna:

DELETE FRÅN anställd VAR Fname = "Ivan" OCH Lname = "Ivanov"

då kommer triggern som kommer att startas vid radering, förutom Ivan Ivanov, även att radera Ivan Sergeev och Mikhail Ivanov. Efter denna borttagning kommer avtryckaren att startas igen och kommer att söka efter alla Ivanovs och Mikhails, såväl som Ivanovs och Sergeevs. Som ett resultat av sitt arbete kommer Petr Sergeev att tas bort. Då kommer samma trigger att ta bort Peter Vasiliev. Efter detta kommer utlösaren att leta efter Petrov och Vasilyev, men eftersom de inte längre finns i tabellen kommer avrättningen att sluta där.

Observera att OM FINNS-kontrollen måste göras här. Om detta inte görs, när det gäller att ta bort Peter Vasiliev, kommer DELETE-instruktionen att exekveras och även om den faktiskt inte tar bort någon, kommer den nyligen anropade triggern att anropa sig själv igen (igen utan att faktiskt radera någon), etc., tills maxnivån överskrids kapslingsnivå 32. Efter att ha nått kapslingsnivå 32 kommer ett fel att uppstå och alla åtgärder avbryts.

Exempel 3. Indirekt rekursion

Låt oss ändra exempel 1 så att om en rad raderas från försäljningstabellen, så skulle även butiken där den raderade försäljningen gjordes tas bort. Eftersom förhållandet mellan dessa tabeller är 1:M kan det bli många försäljningar i butiken som raderas, och inte bara den vi försöker ta bort. Därför bör kedjan vara som följer: ta bort rean → ta bort butiken där den gjordes, → ta bort alla andra försäljningar gjorda i denna butik, → ta bort alla rabatter som är kopplade till denna butik. Dessutom kommer vi att implementera dessa triggers i form av I STÄLLET FÖR triggers så att det inte finns något behov av att bryta kopplingar mellan tabeller.

SKAPA TRIGGER Tri_Del_Sales
På rea
I STÄLLET FÖR DELETE
SOM
TA BORT FRÅN Försäljning FRÅN Försäljning s JOIN Raderad d på d.ord_num = s.ord_num
OM FINNS (VÄLJ * FRÅN Butiker s JOIN Raderad d PÅ d.stor_id = s.stor_id)
DELETE FROM Butiker FRÅN Butiker s JOIN Raderade d PÅ d.stor_id = s.stor_id

SKAPA TRIGGER Tri_Del_Stores
ON butiker
I STÄLLET FÖR DELETE
SOM
RADERA FRÅN Rabatter FRÅN Rabatter di GÅ MED Borttagen de on di.stor_id=de.stor_id
OM FINNS(VÄLJ * FRÅN Försäljning s JOIN Raderad d på d.stor_id = s.stor_id)
RADERA FRÅN Försäljning FRÅN Försäljning s GÅ MED Raderad d på d.stor_id = s.stor_id
DELETE FROM Butiker FRÅN Butiker s JOIN Raderade d på d.stor_id = s.stor_id

För att kontrollera kan du köra kommandot:

DELETE FROM Sales WHERE ord_num = "P723"

Som ett resultat kommer inte bara raden med beställningskoden "P723" att raderas från försäljningstabellen, utan även tre andra rader relaterade till samma butik (kod 8042). Själva butiken 8042 och rabatten som är kopplad till den kommer också att raderas.

I exemplet ovan tas bland annat alla meddelandeutgångar bort och anrop till DELETE-satser ändras eftersom det inte finns några meddelandeutgångar, det finns inget behov av att generera värdet på den lokala variabeln @sStroID . Användningen av denna variabel i DELETE-satsen begränsade något tillämpligheten av triggers. Således var triggers i exempel 2 utformade för att radera poster för endast en butik, och när man raderade poster relaterade till flera butiker samtidigt, fungerade de inte korrekt. Nu finns det ingen sådan begränsning, eftersom alla poster som är associerade med poster i tabellen Borttaget raderas (det vill säga med alla rader faktiskt raderade).

Man kan fråga sig: varför använda rekursion? Skulle det inte vara lättare, när man tar bort från försäljningstabellen, att ta bort i en trigger på den alla poster från sig själv som hänför sig till samma butik som den raderade försäljningsraden, sedan ta bort raden från butikstabellen och i en trigger i tabellen Butiker ta bort relaterade poster endast från tabellen Rabatter? Ja, detta kan göras, men bara om vi alltid ger raderingskommandot specifikt från försäljningstabellen (som gjordes ovan under kontrollen). Däremot kan vi utfärda ett raderingskommando från tabellen Stores, till exempel:

DELETE FROM stores WHERE stor_id = 8042

Och i det här fallet vill vi också att kommandot ska fungera korrekt. Om triggern i butikstabellen, som föreslås i frågan, inte inkluderar radering från försäljning, då kommer en sådan radering att resultera i ett fel om det finns försäljning för butiken som tas bort. Vårt exempel tillåter oss att lösa detta problem. Tja, om utlösaren på butiker innehåller ett kommando för att ta bort från försäljning, så i utlösaren på försäljning finns det inget behov av att inkludera radering av försäljning i samma butik som den som tas bort, eftersom detta kommer att utföras automatiskt genom rekursion.

Obs 1: För att förhindra att triggers som redan skapats i tidigare exempel stör, måste du ta bort dem med hjälp av instruktionen SLOPP TRIGGER trigger_name.

Note 2: Återigen, observera att för att rekursion ska fungera måste lämpliga databas- och serveralternativ ställas in.

Exempel 4

I det sista exemplet, överväg fallet med att definiera flera utlösare för en tabellmodifieringsoperation:

SKAPA TRIGGER trig_del_l PÅ författare FÖR DELETE AS
SKRIV UT "Ta bort trigger #1"

SKAPA TRIGGER trig_del_2 PÅ författare FÖR DELETE AS
SKRIV UT "Ta bort trigger #2"

SKAPA TRIGGER trig_upd_l PÅ författare FÖR UPPDATERING SOM
SKRIV UT "Uppdatera trigger #1"

SKAPA TRIGGER trig_upd_3 PÅ författare FÖR UPPDATERING SOM
SKRIV UT "Uppdatera trigger #3" "

SKAPA TRIGGER trig_upd_2 PÅ författare FÖR UPPDATERING SOM
SKRIV UT "Uppdatera trigger #2"

Låt oss nu försöka ändra någon post tabell:

UPPDATERA Författare
SET au_fname = "Yuri" WHERE au_lname = "Tikhomirov";

Alla tre uppdateringsutlösare kommer att fungera:

Uppdatera trigger #1

Uppdatera trigger #3

Uppdatera trigger #2

Var uppmärksam på exekveringssekvensen av triggers: den bestäms av den ordning i vilken de skapas. Om vi ​​nu tar bort triggern trig_upd_3 och sedan skapar den igen, så får vi följande resultat när vi uppdaterar tabellen:

Uppdatera trigger #1

Uppdatera trigger #2

Uppdatera trigger #3

Flera triggers används ganska aktivt under replikering.

4. Visa triggerinformation och ändra trigger

För att ta reda på syftet med en tabells utlösare måste du visa information som beskriver alla utlösare som tabellen äger. Det finns flera sätt att få information om en specifik tabells utlösare. En av dem är SQL Server Enterprise Manager, den andra är sp_help och sp_depends systemprocedurer. Följ dessa steg för att visa triggertexten via Enterprise Manager:

  1. I Enterprise Manager väljer du den server och databas du vill arbeta med.
  2. Öppna tabellen i designläge med kommandot Design Table och klicka på knappen Utlösare i verktygsfältet i dess fönster.
  3. Dialogrutan Skapa utlösare visas, där du kan se texten för alla installerade utlösare.

De systemlagrade procedurerna sp_help och sp_depends har redan beskrivits i ämnet "Lagrade procedurer".

För att ändra funktionaliteten för en utlösare kan du antingen ta bort den och skapa en ny med lämpliga ändringar, eller ändra en befintlig. För att ändra en befintlig trigger i T-SQL finns kommandot ALTER TRIGGER. Dess syntax liknar den för CREATE TRIGGER-kommandot, förutom att den använder nyckelordet ALTER istället för CREATE.

Du kan också ändra utlösaren med Enterprise Manager. För att göra detta, efter att ha loggat in på Enterprise Manager, behöver du bara göra ändringar och tillämpa dem.

5. Ta bort triggers

Ibland behöver du ta bort triggers från en eller flera tabeller. Om du till exempel flyttar din applikation till produktion kan du behöva ta bort de utlösare som gavs hög kvalitet bearbetning, men kraftigt minskad produktivitet. Du kan helt enkelt ta bort triggers för att ersätta dem med fler ny version. För att ta bort en trigger, använd DROP TRIGGER-satsen:

SLOPP TRIGGER [ägare.]trigger_name [, n]

Att ta bort en utlösare är valfritt om den nya utlösaren ersätter en befintlig. När du släpper en tabell förstörs alla objekt som är associerade med den automatiskt, inklusive triggers.

Exempel på att ta bort Tri_Dei_Autnors-utlösaren:

SLOPP TRIGGER Tri_Del_Authors

6. Pausa och återuppta triggers

Det är ofta nödvändigt att inaktivera en utlösare ett tag utan att faktiskt radera den. Detta kan uppnås med hjälp av designen ÄNDRA TABELL<имя_таблицы>INAKTIVERA TRIGGER<имя триггера> för att inaktivera utlösaren och ÄNDRA TABELL<имя_таблицы>AKTIVERA TRIGGER<имя триггера> att återuppta sitt arbete.

Arbetsuppgifter för självständigt arbete

Innan vi börjar utföra uppgifter, låt oss påminna dig om att triggers är systemlagrade procedurer som är associerade med en specifik tabell. För att anropa triggereditorn måste du välja tabellen efter höger knapp snabbmenyn gå till avsnittet Alla uppgifter > Hantera utlösare, och du kommer till triggereditorn (Fig. 1).

Ris. 1. Initialt tillstånd för triggerredigeraren när du skapar en ny trigger

Uppgift 1. Utveckla en trigger som skulle radera en post om en bok om det sista exemplaret av den här boken raderas. Vilken tabell kommer du att skriva denna trigger för? När du skriver en trigger, kom ihåg att tabellen "Böcker" är associerad med "Författare" och " Systemkatalog" De är dock relaterade av en många-till-många-relation, för vilken länktabeller används. Du kan inte ta bort data om en bok om den har länkar i dessa länkningstabeller. Överväg att ta bort data från länkningstabeller först. Kontrollera funktionen hos denna utlösare.

Uppgift 2. Utveckla en trigger som inte skulle tillåta radering av en bokinstans om den här instansen finns i det här ögonblicketär i läsarens händer. För att avbryta kommandot delete, använd kommandot ROLLBACK transaktionsåterställning.

Kontrollera utlösarens funktion i oberoende läge genom att försöka ta bort inte det sista exemplaret av boken som har ett märke som indikerar att den är i läsarens ägo.

Försök att ta bort ett exemplar av boken som inte finns i läsarens händer.

Kontrollera funktionen hos de två triggarna genom att försöka ta bort det sista exemplaret av boken som finns i läsarens händer.

Uppgift 3. Utveckla en trigger som skulle kontrollera utgivningen av böcker till en läsare och, om antalet ej levererade böcker till hands överstiger tre, inte skulle tillåta att ytterligare en bok ges ut till denna läsare.

Uppgift 4. Utveckla en trigger som skulle lägga till en instans när en ny bok skrivs in. Faktum är att vi har bestämt att böcker endast finns i vår katalog om de finns i vårt bibliotek, därför bör ett exemplar av denna bok läggas till i tabellen "Kopiera" när du anger en ny bok.

Uppgift 5. Utveckla en trigger av typen I STÄLLET FÖR för tabellen "Läsare". Denna utlösare ska kontrollera om det finns information om minst en av telefonerna för snabb kommunikation med läsaren, och om det inte finns sådan information, skriv inte in data om läsaren.

Uppgift 6. Utveckla en trigger som, när värdet på ett fält som symboliserar närvaron av en bokkopia i biblioteket, till exempel YES_NO, ändras från "1" till "0", automatiskt skulle ersätta värdena i "Problem" datum, "Returdatum" och "Bibliotekskortsnummer"-fälten "till obestämd tid.

Uppgift 7. Utveckla en trigger som inte tillåter dig att radera en läsare om han har minst en bok från biblioteket.

Uppgift 8. Utveckla en trigger som, när en kopia av en bok raderas, skulle kontrollera hur många exemplar av den här boken som finns kvar i biblioteket, och om det bara finns ett exemplar kvar, skulle det höja priset på den här boken med 15 % lika sällsynt och värdefullt.

tryckt version

Definitionen av en utlösare, omfattningen av dess användning, platsen och rollen för utlösaren för att säkerställa dataintegritet anges. Typer av triggers beskrivs. Operatörer för att skapa, ändra och ta bort en utlösare övervägs. Triggerprogrammering illustreras med exempel på att skapa triggers för att implementera integritetsbegränsningar och samla in statistisk data.

Trigger Definition i SQL Language Standard

Triggers är en typ av lagrad procedur. De exekveras när en DML-operator (datamanipulation language) exekveras på bordet. Triggers används för att kontrollera dataintegritet och även för att återställa transaktioner.

En trigger är en kompilerad SQL-procedur, vars exekvering är betingad av förekomsten av vissa händelser inom relationsbas data. Användningen av triggers är för det mesta mycket bekvämt för databasanvändare. Ändå innebär deras användning ofta extra resurskostnader för I/O-operationer. I de fall där samma resultat (med mycket mindre resursoverhead) kan uppnås med hjälp av lagrade procedurer eller applikationsprogram, är användningen av triggers olämplig.

Triggers är ett speciellt SQL-serververktyg som används för att upprätthålla dataintegriteten i en databas. Integritetsbegränsningar, regler och standardinställningar kanske inte alltid uppnår den önskade funktionalitetsnivån. Det är ofta nödvändigt att implementera komplexa dataverifieringsalgoritmer för att säkerställa deras tillförlitlighet och verklighet. Dessutom är det ibland nödvändigt att spåra ändringar i tabellvärden för att kunna på rätt sättändra relaterade data. Triggers kan ses som ett slags filter som träder i kraft efter att alla operationer har genomförts i enlighet med regler, standardvärden etc.

En utlösare är en speciell typ av lagrad procedur som startas automatiskt av servern när ett försök görs att ändra data i de tabeller som utlösarna är kopplade till. Varje utlösare är associerad med en specifik tabell. Alla dataändringar som den gör betraktas som en transaktion. Om ett fel eller dataintegritetsintrång upptäcks återställs transaktionen. Ändringar är därför förbjudna. Alla ändringar som redan gjorts av utlösaren ångras också.

Endast databasägaren kan skapa en utlösare. Denna begränsning låter dig undvika oavsiktliga ändringar av tabellstrukturen, sätt att koppla andra objekt till dem, etc.

Avtryckaren är ett mycket användbart och samtidigt farligt verktyg. Så om logiken för dess operation är felaktig kan du enkelt förstöra en hel databas, så triggers måste felsökas mycket noggrant.

Till skillnad från en vanlig rutin, exekveras en trigger implicit varje gång den inträffar. utlösa händelse, dessutom har det inga argument. Att aktivera den kallas ibland att avfyra en avtryckare. Med hjälp av triggers uppnås följande mål:

  • Validera korrektheten av inmatade data och implementera komplexa dataintegritetsbegränsningar som är svåra, för att inte säga omöjliga, att upprätthålla med hjälp av integritetsbegränsningar som ställts in i en tabell;
  • utfärda varningar som påminner dig om att utföra vissa åtgärder när du uppdaterar en tabell implementerad på ett visst sätt;
  • ackumulering av revisionsinformation genom att registrera information om de ändringar som gjorts och de personer som utförde dem;
  • replikeringsstöd.

Det grundläggande formatet för CREATE TRIGGER-kommandot visas nedan:

<Определение_триггера>::= SKAPA TRIGGER trigger_name INNAN | EFTER<триггерное_событие>PÅ<имя_таблицы> <тело_триггера>

utlösa händelser består av att infoga, ta bort och uppdatera rader i en tabell. I det senare fallet för utlösa händelse Du kan ange specifika tabellkolumnnamn. Utlösningstiden bestäms med hjälp av nyckelord FÖRE (utlösaren aktiveras innan de händelser som är associerade med den exekveras) eller EFTER (efter att de exekveras).

Åtgärderna som utförs av utlösaren specificeras för varje rad (FÖR VARJE RAD) som täcks av en given händelse, eller endast en gång för varje händelse (FÖR VARJE UTTALANDE).

Beteckning <список_старых_или_новых_псевдонимов> hänvisar till komponenter som gammal eller ny linje (GAMMEL / NY ) eller gammal eller nytt bord(GAMMEL BORD / NYTT BORD). Det är tydligt att de gamla värdena inte gäller för att infoga händelser, och de nya värdena gäller inte för att radera händelser.

Givet att korrekt användning Triggers kan vara en mycket kraftfull mekanism. Deras främsta fördel är det standardfunktioner lagras i databasen och aktiveras konsekvent varje gång den uppdateras. Detta kan avsevärt förenkla applikationer. Det är dock värt att nämna de inneboende nackdelarna med triggern:

  • komplexitet: när vissa funktioner flyttas till databasen blir uppgifterna för dess design, implementering och administration mer komplexa;
  • Dold funktionalitet: Att flytta viss funktionalitet till en databas och lagra den som en eller flera triggers resulterar ibland i att någon funktionalitet döljs för användaren. Även om detta förenklar driften till viss del, kan det tyvärr orsaka oavsiktliga, potentiellt oönskade och skadliga biverkningar, eftersom användaren i det här fallet inte kan kontrollera alla processer som sker i databasen;
  • prestandapåverkan: innan varje kommando utförs för att ändra tillståndet för databasen, måste DBMS kontrollera triggervillkoret för att avgöra om en trigger ska aktiveras för detta kommando. Att utföra sådana beräkningar påverkar den övergripande prestandan för DBMS, och vid tider med toppbelastning kan dess minskning bli särskilt märkbar. Uppenbarligen, när antalet triggers ökar, ökar även de omkostnader som är förknippade med sådana operationer.

Felaktigt skrivna triggers kan leda till allvarliga problem, som döda lås. Triggers kan blockera många resurser under lång tid, så du bör vara uppmärksam på Särskild uppmärksamhet för att minimera åtkomstkonflikter.

Implementering av triggers i MS SQL Server-miljö

MS SQL Server DBMS-implementeringen använder följande operatör för att skapa eller ändra utlösare:

<Определение_триггера>::= (SKAPA | ÄNDRA) TRIGGER trigger_name PÅ (tabellnamn | visningsnamn) ( ( ( FÖR | EFTER | I STÄLLET FÖR ) ( [ DELETE] [,] [ INFOGA] [,] [ UPPDATERA] ) [ MED BILAGA ] [ INTE FÖR REPLICATION ] AS sql_statement[...n] ) | ( (FÖR | EFTER | I STÄLLET FÖR ) ( [,] ) [ MED BILAGA] [ INTE FÖR REPLICERING] SOM ( OM UPPDATERING(kolumnnamn) [ (OCH | ELLER) UPPDATERING( kolumnnamn)] [...n] |. IF (COLUMNS_UPDATES() (process_bit_operator) change_bit_mask) (comparison_bit_operator) bit_mask [...n]) sql_operator [...n] )

En trigger kan bara skapas i den aktuella databasen, men det är möjligt att komma åt andra databaser inom triggern, inklusive de som finns på en fjärrserver.

Låt oss titta på syftet med argumenten från CREATE | ALTER TRIGGER.

Triggernamnet måste vara unikt i databasen. Dessutom kan du ange ägarens namn.

När du anger argumentet WITH ENCRYPTION krypterar servern triggerkoden så att ingen, inklusive en administratör, kan komma åt eller läsa den. Kryptering används ofta för att dölja proprietära databehandlingsalgoritmer som är programmerarens immateriella rättigheter eller en affärshemlighet.

Triggertyper

Det finns två alternativ i SQL Server som bestämmer beteendet hos utlösare:

  • EFTER. Utlösaren exekveras efter att de kommandon som anropade den har slutförts. Om kommandona av någon anledning inte kan slutföras framgångsrikt, exekveras inte triggern. Det bör noteras att dataändringar som ett resultat av exekvering av en användarbegäran och triggerexekvering utförs i kroppen av en transaktion: om triggern rullas tillbaka, kommer användarändringar också att avvisas. Du kan definiera flera EFTER-utlösare för varje operation (INSERT, UPDATE, DELETE). Om du har flera AFTER-utlösare på en tabell kan du använda sp_settriggerorder-systemets lagrade procedur för att ange vilken utlösare som ska köras först och vilken som körs sist. Som standard, i SQL Server, är alla utlösare AFTER-utlösare.
  • ISTÄLLET FÖR . Utlösaren anropas istället för att utföra kommandon. Till skillnad från AFTER-utlösaren kan INSTEAD OF-utlösaren definieras för både en tabell och en vy. För varje INSERT-, UPDATE-, DELETE-operation kan endast en INSTEAD OF-utlösare definieras.

Triggers kännetecknas av den typ av kommandon som de svarar på.

Det finns tre typer av triggers:

  • INSERT TRIGGER – Utlöses när ett försök görs att infoga data med kommandot INSERT.
  • UPDATE TRIGGER – utlöses när ett försök görs att ändra data med kommandot UPDATE.
  • DELETE TRIGGER – utlöses när ett försök görs att radera data med kommandot DELETE.

Konstruktioner [ DELETE] [,] [ INFOGA] [,] [ UPPDATERA] Och FÖR | EFTER | ISTÄLLET FÖR ) ([,] avgöra vilket kommando utlösaren ska svara på. När du skapar den måste minst ett kommando anges. Tillåten skapa en trigger, svarar på två eller alla tre kommandon.

WITH APPEND låter dig skapa flera triggers av varje typ.

skapa en trigger med argumentet INTE FÖR REPLIKATION är det förbjudet att köras medan tabeller modifieras av replikeringsmekanismer.

AS sql_operator[...n]-konstruktionen definierar en uppsättning SQL-satser och kommandon som kommer att exekveras när triggern startas.

Observera att ett antal operationer inte är tillåtna i en utlösare, till exempel:

  • skapa, modifiera och ta bort en databas;
  • återhämtning säkerhetskopiering databas eller transaktionslogg.

Dessa kommandon tillåts inte att utföras eftersom de inte kan återställas om transaktionen där triggern utförs återställs. Det är osannolikt att detta förbud på något sätt påverkar funktionen hos skapade triggers. Det är svårt att hitta en situation där du till exempel efter att ha ändrat en tabellrad skulle behöva återställa en säkerhetskopia av transaktionsloggen.

Trigger programmering

När du kör kommandon för att lägga till, ändra och ta bort poster skapar servern två specialtabeller: insatt Och raderade. De innehåller listor över rader som kommer att infogas eller raderas när transaktionen är klar. Strukturen för de infogade och borttagna tabellerna är identisk med strukturen för de tabeller för vilka utlösaren är definierad. Varje utlösare skapar sin egen uppsättning infogade och borttagna tabeller, så ingen annan utlösare kan komma åt dem. Beroende på vilken typ av operation som fick utlösaren att köra, kan innehållet i de infogade och borttagna tabellerna vara olika:

  • INSERT kommando – den infogade tabellen innehåller alla rader som användaren försöker infoga i tabellen; det kommer inte att finnas en enda rad i den raderade tabellen; efter att triggern är klar kommer alla rader från den infogade tabellen att flyttas till källtabellen;
  • DELETE kommando – den raderade tabellen kommer att innehålla alla rader som användaren försöker ta bort; utlösaren kan kontrollera varje rad och avgöra om den är tillåten att raderas; det kommer inte att finnas några rader i den infogade tabellen;
  • UPDATE-kommandot - när det körs innehåller den raderade tabellen gamla radvärden som kommer att raderas efter framgångsrikt slutförande av triggern. De nya radvärdena finns i den infogade tabellen. Dessa rader kommer att läggas till i källtabellen efter att triggern har utförts.

För att få information om antalet rader som kommer att ändras när en trigger slutförs framgångsrikt, kan du använda @@ROWCOUNT; det returnerar antalet rader som bearbetades av det sista kommandot. Det bör betonas att avtryckaren inte aktiveras när ett försök görs att ändra en specifik rad, utan när ändringskommandot utförs. Ett sådant kommando påverkar många rader, så utlösaren måste bearbeta alla dessa rader.

Om utlösaren upptäcker att av 100 rader som infogas, ändras eller tas bort, är det bara en som inte uppfyller vissa villkor, då kommer ingen rad att infogas, ändras eller tas bort. Detta beteende beror på transaktionens krav - antingen måste alla ändringar utföras eller ingen.

En trigger körs som en implicit definierad transaktion, så transaktionskontrollkommandon kan användas inom triggern. Närmare bestämt, när en överträdelse av integritetsbegränsningen upptäcks, måste kommandot ROLLBACK TRANSACTION användas för att avbryta utlösaren och ångra alla ändringar som användaren försökte göra.

Du kan använda funktionen COLUMNS_UPDATED() för att få en lista över kolumner som modifierades av kommandona INSERT eller UPDATE som fick utlösaren att köras. Den returnerar ett binärt tal, där varje bit, som börjar med den minst signifikanta biten, motsvarar en kolumn i tabellen (i kolumnernas ordning när tabellen skapades). Om en bit är satt till "1", har motsvarande kolumn ändrats. Dessutom bestäms det faktum att en kolumn har ändrats av UPDATE-funktionen (kolumnnamn).

För ta bort avtryckaren kommandot används

SLAPP TRIGGER (trigger_name) [,...n]

Här är exempel på användning av triggers.

Exempel 14.1. Använda en trigger för att genomförande av värdebegränsningar. I posten som läggs till i Transaktionstabellen får mängden av den sålda produkten inte vara mindre än saldot från Lagertabellen.

Kommandot för att infoga en post i Deal-tabellen kan till exempel vara så här:

INFOGA I Handelsvärden (3,1,-299,"01/08/2002")

Den skapade utlösaren bör reagera på dess utförande på följande sätt: det är nödvändigt att avbryta kommandot om i lagertabellen produktbalansen är mindre än den sålda kvantiteten av produkten med den angivna koden (i exemplet, produktkod = 3 ). I den infogade posten anges produktens kvantitet med ett "+"-tecken om produkten levereras och med ett "-"-tecken om den säljs. Den presenterade utlösaren är konfigurerad att endast bearbeta en tillagd post.

SKAPA TRIGGER Trigger_ins PÅ Transaktion FÖR INFOGA SOM OM @@ROWCOUNT=1 BÖRJA OM INTE FINNS(VÄLJ * FRÅN infogat WHERE -inserted.quantity<=ALL(SELECT Склад.Остаток FROM Склад,Сделка WHERE Склад.КодТовара= Сделка.КодТовара)) BEGIN ROLLBACK TRAN PRINT "Отмена поставки: товара на складе нет" END END Exempel 14.1. Använda en utlösare för att implementera begränsningar på ett värde.

Exempel 14.2. Använda en trigger för att samla in statistisk data.

Skapa en utlösare för att bearbeta operationen att infoga en post i Deal-tabellen, till exempel följande kommando:

INFOGA I Handelsvärden (3,1,200,"01/08/2002")

Produkt med kod 3 levereras från kund med kod 1 i mängden 200 enheter.

Vid försäljning eller mottagande av en vara måste lagermängden anpassas därefter. Om produkten ännu inte finns i lager måste du lägga till en motsvarande post i lagertabellen. Utlösaren bearbetar endast en tillagd rad.

ALTER TRIGGER Trigger_ins PÅ Transaktion FÖR INSERT AS DECLARE @x INT, @y INT IF @@ROWCOUNT=1 --en post läggs till i Transaktionstabellen om leverans av varor BEGIN --mängden sålda varor får inte vara -- mindre än saldot från Warehouse-tabellen OM INTE FINNS(SELECT * FROM inserted WHERE -inserted.quantity< =ALL(SELECT Склад.Остаток FROM Склад,Сделка WHERE Склад.КодТовара= Сделка.КодТовара)) BEGIN ROLLBACK TRAN PRINT "откат товара нет " END --если записи о поставленном товаре еще нет, --добавляется соответствующая запись --в таблицу Склад IF NOT EXISTS (SELECT * FROM Склад С, inserted i WHERE С.КодТовара=i.КодТовара) INSERT INTO Склад (КодТовара,Остаток) ELSE --если запись о товаре уже была в таблице --Склад, то определяется код и количество --товара издобавленной в таблицу Сделка записи BEGIN SELECT @y=i.КодТовара, @x=i.Количество FROM Сделка С, inserted i WHERE С.КодТовара=i.КодТовара --и производится изменения количества товара в --таблице Склад UPDATE Склад SET Остаток=остаток+@x WHERE КодТовара=@y END END Exempel 14.2. Använda en trigger för att samla in statistisk data.

Exempel 14.3. Skapa en utlösare för att bearbeta operationen att ta bort en post från tabellen Deal, till exempel följande kommando:

För produkten vars kod angavs när posten raderades är det nödvändigt att justera dess lagersaldo. Utlösaren bearbetar endast en post som ska raderas.

SKAPA TRIGGER Trigger_del PÅ Transaktion FÖR DELETE AS IF @@ROWCOUNT=1 -- en post raderas BÖRJA DECLARE @y INT,@x INT --koden och kvantiteten för produkten bestäms från posten -- raderas från Warehouse-tabellen VÄLJ @y=ProductCode, @ x=Quantity FROM raderad --i lagertabellen justeras mängden --artikel UPPDATERA Warehouse SET Remaining=Remaining-@x WHERE Product Code=@y END Exempel 14.3. Trigger för att bearbeta operationen att ta bort en post från en tabell

Exempel 14.4. Skapa en utlösare för att bearbeta operationen att ändra en post i tabellen Deal, till exempel med följande kommando:

i alla transaktioner med varor med en kod lika med 3, minska mängden varor med 10 enheter.

Det angivna kommandot kan leda till ändringar i flera poster samtidigt i tabellen Deal. Därför kommer vi att visa hur man skapar en trigger som bearbetar mer än en post. För varje ändrad post är det nödvändigt för den gamla (före ändringen) produktkoden att reducera saldot av produkten i lagret med värdet av den gamla (före ändringen) kvantitet av produkten och för den nya (efter ändra) produktkod för att öka saldot i lagret med värdet av det nya (efter ändringen) värdet. För att bearbeta alla ändrade poster kommer vi att introducera markörer där vi sparar alla gamla (från den raderade tabellen) och alla nya värden (från den infogade tabellen).

SKAPA TRIGGER Trigger_upd PÅ Transaktion FÖR UPPDATERING SOM DECLARE @x INT, @x_old INT, @y INT, @y_old INT -- markör med nya värden DECLARE CUR1 CURSOR FOR SELECT Produktkod, Kvantitet FROM infogat -- markör med gamla värden ​​DECLARE CUR2 CURSOR FÖR VALD produktkod, kvantitet FRÅN raderad OPEN CUR1 OPEN CUR2 -- flytta parallellt genom båda markörerna HÄMTA NÄSTA FRÅN CUR1 INTO @x, @y HÄMTA NÄSTA FRÅN CUR2 INTO @x_old, @y_old MEDAN @@FETCH_STATUS= BÖRJA -- för den gamla produktkoden minskar den -- kvantiteten i lagret UPPDATERA Lager SET Remaining=Remaining-@y_old WHERE Product Code=@x_old --för en ny produktkod, om en sådan produkt ännu inte finns i lager, en ny post läggs in OM INTE FINNS (VÄLJ * FRÅN Warehouse WHERE Product Code=@x) INSERT INTO Warehouse(Produktkod, Återstående) VÄRDEN (@x,@y) ANNAT -- annars för en ny produktkod ökar den -- dess kvantitet i lager UPPDATERA Lager SET Remaining=Remaining+@y WHERE Product Code=@x HÄMTA NÄSTA FRÅN CUR1 INTO @x, @y HÄMTA NÄSTA FRÅN CUR2 INTO @x_old, @y_old AVSLUTA STÄNG CUR1 STÄNG CUR2 AVALLOKERA CUR1 DEALLOCATE CUR2 Exempel 14.4. trigger för att bearbeta en operation för att ändra en post i en tabell

I den övervägda triggern finns det ingen jämförelse av mängden varor när en transaktionspost ändras med dess saldo i lagret.

Exempel 14.5. Låt oss rätta till denna brist. För att generera ett felmeddelande använder vi MS SQL Server RAISERROR-kommandot i utlösarens kropp, vars argument är meddelandetexten, allvarlighetsgrad och felstatus.

ÄNDRA TRIGGER Trigger_upd PÅ Transaktion FÖR UPPDATERING SOM DECLARE @x INT, @x_old INT, @y INT, @y_old INT ,@o INT DECLARE CUR1 CURSOR FÖR SELECT Artikelkod, Kvantitet FRÅN infogat DECLARE CUR2 CURSOR FÖR SELECT Artikelkod, raderad kvantitet ÖPPNA CUR1 ÖPPNA CUR2 HÄMTA NÄSTA FRÅN CUR1 INTO @x, @y HÄMTA NÄSTA FRÅN CUR2 INTO @x_old, @y_old MEDAN @@FETCH_STATUS=0 BÖRJA VÄLJ @o=återstående FRÅN lager VAR produktkod=@x IF @o<-@y BEGIN RAISERROR("откат",16,10) CLOSE CUR1 CLOSE CUR2 DEALLOCATE CUR1 DEALLOCATE CUR22 ROLLBACK TRAN RETURN END UPDATE Склад SET Остаток=Остаток-@y_old WHERE КодТовара=@x_old IF NOT EXISTS (SELECT * FROM Склад WHERE КодТовара=@x) INSERT INTO Склад(КодТовара,Остаток) VALUES (@x,@y) ELSE UPDATE Склад SET Остаток=Остаток+@y WHERE КодТовара=@x FETCH NEXT FROM CUR1 INTO @x, @y FETCH NEXT FROM CUR2 INTO @x_old, @y_old END CLOSE CUR1 CLOSE CUR2 DEALLOCATE CUR1 DEALLOCATE CUR2 Exempel 14.5. Korrigerad version av utlösaren för att bearbeta operationen för att ändra en post i en tabell

Exempel 14.6. I exemplet avbryts alla ändringar om det är omöjligt att implementera minst en av dem. Låt oss skapa en utlösare som låter dig avbryta ändringar av endast vissa poster och ändra resten.

I det här fallet exekveras inte triggern efter att posterna har ändrats, utan istället för ändringskommandot.

ALTER TRIGGER Trigger_upd PÅ Transaktion I STÄLLET FÖR UPPDATERA SOM DECLARE @k INT, @k_old INT DECLARE @x INT, @x_old INT, @y INT DECLARE @y_old INT ,@o INT DECLARE CUR1 CURSOR FOR SELECT Transaction Code, Product Code, Quantity FROM infogat DECLARE CUR2 CURSOR FÖR VALD Transaktionskod, Produktkod, Kvantitet FRÅN raderad OPEN CUR1 ÖPPNA CUR2 HÄMTA NÄSTA FRÅN CUR1 INTO @k,@x, @y HÄMTA NÄSTA FRÅN CUR2 INTO @k_old,@x_old, @y_old WHILE @@TUS=FETCH 0 BÖRJA VÄLJ @ o=återstående FRÅN lagret VAR Produktkod=@x OM @o>=-@y BÖRJA HÖJNING("ändra",16,10) UPPDATERA Transaktions SET kvantitet=@y, Produktkod=@x VAR Transaktionskod =@k UPPDATERA Warehouse SET Remaining =Remaining-@y_old WHERE Artikelkod=@x_old OM INTE FINNS (VÄLJ * FRÅN Warehouse WHERE Artikelkod=@x) INFOGA I Warehouse(Artikelkod, Återstående) VÄRDEN (@x,@y) ANDERS UPPDATERA Warehouse SET Remaining=Remaining+@y WHERE Item Code=@x END ELSE RAISERROR("post ej ändrad",16,10) HÄMTA NÄSTA FRÅN CUR1 INTO @k,@x, @y HÄMTA NÄSTA FRÅN CUR2 INTO @k_old, @x_old, @y_old SLUTA STÄNG CUR1 STÄNG CUR2 AVALLOKERA CUR1 AVALLOKERA CUR2 Exempel 14.6. En utlösare som låter dig ångra ändringar i endast vissa poster och göra ändringar i resten.

  • SQL
  • Webbplatsutveckling
  • Det finns redan många artiklar på Internet om sql-utlösare, men jag lägger till en till med adekvata exempel för att förstärka materialet för dem som är "in the know" och för att bättre förstå materialet för dem som precis har börjat förstå "zen av sql". Samtidigt kommer jag att skapa en diskussion om ämnet.

    Låt mig säga direkt att min åsikt bara är min åsikt, och ibland är den väldigt kategorisk. Av flera anledningar måste du arbeta med mycket laddade webbplatser och komplexa webbapplikationer.

    En värdefull erfarenhet från arbetet med dem var att hålla reda på prioriteringar och statistik. Vad betyder det? Det är enkelt: om du har en blogg och den har 2-3-4-10012 miljoner besökare per dag, och artiklar skrivs bara 1-2-3-3435 gånger om dagen (en storleksordning mindre än antalet visningar) , då kan hastigheten för att spara artikeln (och komplexiteten av detta) i förhållande till hastigheten för visning av artikeln vara proportionellt mindre. Ju mer vi visar, desto mer kritiskt är det visningen och inte sparandet av artikeln/sidan/tabellen. Vilket inte betyder att du kan slappna av. Att spara en artikel på 3-5-10 sekunder på en blogg är inom gränserna för tillräcklighet, men att generera en sida på mer än 2 sekunder (+ medan skript och stilar med bilder laddas) är på gränsen till "vilken långsam sida , jag ska läsa något annat" , och ännu värre, "jag ska köpa den någon annanstans."

    Om vi ​​tar en genomsnittlig webbplats med röstning/karma, kommentarer, sidvisningsräknare, etc., kommer många utvecklare omedelbart att tänka på med konstruktioner som SELECT count(*) FROM comment WHERE comment.page=page_id. Tja, tänk bara på att beräkna antalet betyg och antalet kommentarer för varje artikel. Åh, vi har 10 artiklar från varje avsnitt på huvudsidan. Med en trafik på 10 personer per sekund, på en genomsnittlig VPS, har du råd med 60-100 SQL-frågor per sida (hej, Bitrix).

    Men åt helvete med texten (jag är nog redan trött på det). Bar data:

    bloggbord

    SKAPA TABELL OM INTE FINNS `blogg` (`id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(128) NOT NULL, `text` text NOT NULL, `creation` datetime NOT NULL, `modification` datetime NOT NULL , `img` varchar(128) NOT NULL DEFAULT "default.png", `status` tinyint(4) NOT NULL DEFAULT "2", `user_id` int(11) NOT NULL, `rate` int(11) NOT NULL , `relax_type` tinyint(4) NOT NULL, `timers` tidsstämpel NOT NULL DEFAULT CURRENT_TIMESTAMP, `contest` tinyint(1) NOT NULL DEFAULT "0", `views` int(11) NOT NULL DEFAULT "0", `comment ` int(11) NOT NULL, `url` varchar(128) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `url` (`url`), KEY `country_id` (`country_id`), KEY `user_id` ` (`användar-id`), KEY `status` (`status`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1456435 ;

    Kommentarstabell

    SKAPA TABELL OM INTE FINNS `kommentarer` (`owner_name` varchar(50) NOT NULL, `owner_id` int(12) NOT NULL, `id` int(12) NOT NULL AUTO_INCREMENT, `parent_id` int(12) DEFAULT NULL, `user_id` int(12) DEFAULT NULL, `text` text, `creation` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `status` int(1) NOT NULL DEFAULT "0", PRIMÄRNYCKEL (`id`), KEY `ägare_namn` ( `owner_name`,`owner_id`), KEY `parent_id` (`parent_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=243254252 ;

    Som du kan se har varje artikel i bloggtabellen en kommentarsräknare (kommentarfält).
    Enkel övning:
    1. Lade till en kommentar - ökade räknaren för bloggen
    2. Raderade/gömde kommentaren - minskade räknaren.
    Att göra detta i kod är bekvämt och bekant, men det finns ett bekvämare verktyg - triggers.

    Och så, vi har 2 händelser (faktiskt 3): skapandet av en kommentar och dess radering (den tredje händelsen är en förändring av dess status ("radering", förbud, etc.).
    Låt oss bara överväga att skapa och ta bort, och låt ändra status vara din läxa.

    Det finns en funktion i exemplet: kommentarer kan vara för flera typer av artiklar.

    Skapa en kommentar:

    SKAPA TRIGGER `add_count_comment` EFTER INFOGA PÅ `kommentarer` FÖR VARJE RAD BEGIN // i användarens personliga konto kommer vi att räkna hur många kommentarer han skrev UPPDATERA användare SET user.countcomment= user.countcomment+1 WHERE user.id = NEW.user_id ; // bestäm vad kommentaren hänvisar till och öka omedelbart räknaren i dessa tabeller CASE NEW.`owner_name` NÄR "Blogg" SEDAN UPPDATERA `blogg` SET `blogg`.`comment` = `blogg`.`comment`+1 WHERE `blogg `.id = NYTT.`ägare-id` ; NÄR "Artikel" DÅ UPPDATERAS `artikel` SET `artikel`.`comment` = `artikel`.`kommentar`+1 WHERE `artikel`.`id` = NYTT.`ägare_id` ; NÄR "PopulatePlace" DÅ UPPDATERAS `populate_place` SET `populate_place`.`comment` = `populate_place`.`comment`+1 WHERE `populate_place`.`id` = NEW.`owner_id` ; SLUT FALL; // här gör vi det lättare för oss själva att arbeta med nyhetsflöden // vi skriver artikelns url direkt, så att vi DÅ inte behöver göra onödiga val CASE NEW.`ägare_namn` NÄR "Blogg" SEDAN STÄLL IN userurl = (VÄLJ URL FRÅN `blogg` VAR `blogg`. id= NYTT.`ägare_id`); NÄR "Artikel" THEN SET userurl = (VÄLJ URL FRÅN `artikel` WHERE article.id=NEW.`ägare_id`); NÄR "PopulatePlace" SÄT SET userurl = ``; SLUT FALL; // skriv rubriken på artikeln direkt för att inte göra ett val. DETTA CASE NEW.`owner_name` NÄR "Blogg" THEN SET usertitle = (välj titel från `blogg` där blog.id=NEW.`owner_id`) ; NÄR "Artikel" DÅ STÄLL IN usertitle = (välj titel från `artikel` där article.id=NEW.`owner_id`); NÄR "PopulatePlace" DÅ STÄLL IN usertitle = ` `; SLUT FALL; INSERT INTO user_has_events VALUES (NEW.user_id,NEW.id,"Comments",NOW(),userurl, usertitle); SLUTET

    Detsamma gäller för att ta bort en kommentar:

    SKAPA TRIGGER `del_count_comment` EFTER DELETE PÅ `kommentarer` FÖR VARJE RAD BÖRJA UPPDATERA användare SET user.countcomment= user.countcomment -1 WHERE user.id = OLD.user_id; CASE OLD.`owner_name` NÄR "Blogg" DÅ UPPDATERA `blogg` SET `blog`.`comment` = `blogg`.`comment`-1 WHERE `blogg`.`id` = OLD.`owner_id` ; NÄR "Artikel" DÅ UPPDATERA `artikel` SET `artikel`.`comment` = `artikel`.`kommentar`-1 WHERE `artikel`.`id` = OLD.`owner_id` ; NÄR "PopulatePlace" DÅ UPPDATERAS `populate_place` SET `populate_place`.`comment` = `populate_place`.`comment`-1 WHERE `populate_place`.`id` = OLD.`owner_id` ; SLUT FALL; SLUTET

    Och så vad vi fick:
    1. När vi infogade en kommentar beräknade vi automatiskt mängden kommentarer för ett specifikt kommentarobjekt (artikel, sida, not) med hjälp av SQL-servern.
    2. Vi har skapat ett nyhetsflöde (hej alla sociala nätverk, etc.)
    3. När du tar bort en kommentar drar vi av all data.
    4. Vi använde inga ramverksverktyg.
    5. Hämtning av all nödvändig data sker snabbt (endast 1 begäran vid visning av en sida, med undantag för andra "vänster" data på den.)

    Vi har även sfinx, som med jämna mellanrum gör urval av artiklar som har ändrats den senaste minuten. För detta ändamål har bloggen ett ändringsfält.

    Trigger lade till:

    SKAPA TRIGGER `ins_blog` INNAN INSERT ON `blogg` // infoga tiden innan du sparar informationen genom att "ersätta" data. FÖR VARJE RAD BEGIN SET NEW.modification = NOW(); SLUTET

    När vi nu gör ett urval för sista minuten kommer vi att få alla dokument som lades till i sista minuten.

    SKAPA TRIGGER `ins_blog` INNAN UPPDATERING PÅ `blogg` // infoga tiden innan du sparar informationen genom att "ersätta" data. FÖR VARJE RAD BEGIN SET NEW.modification = NOW(); SLUTET

    Om uppgifterna ändras kommer vi också att uppdatera sökindexet.

    Vanligtvis, i ett genomsnittligt projekt, överförs allt som kan överföras till sql-serversidan. SQL-servern själv utför sådana operationer snabbare och med färre resurser än vad som kan göras med det programmeringsspråk som används.

    UPD: Holivaren som ägnas åt möjligheten att komplicera databasens struktur förklaras öppen.

    Senast uppdaterad: 2017-11-09

    Triggers är en speciell typ av lagrad procedur som anropas automatiskt när en viss åtgärd utförs på en tabell eller vy, i synnerhet när man lägger till, ändrar eller tar bort data, det vill säga när man utför INSERT, UPDATE, DELETE-kommandon.

    Formell definition av en trigger:

    SKAPA TRIGGER trigger_name PÅ (tabellnamn | visningsnamn) (EFTER | I STÄLLET FÖR) SOM sql_expressions

    För att skapa en trigger, använd CREATE TRIGGER-satsen följt av triggernamnet. Vanligtvis återspeglar triggernamnet typen av operation och namnet på tabellen där operationen utförs.

    Varje utlösare är associerad med en specifik tabell eller vy, vars namn anges efter ordet PÅ .

    Sedan är triggertypen inställd. Vi kan använda en av två typer:

      EFTER: Körs efter att åtgärden är klar. Definieras endast för tabeller.

      I STÄLLET FÖR: exekveras istället för en åtgärd (det vill säga att åtgärden - lägga till, ändra eller ta bort - utförs inte alls). Definierat för tabeller och vyer

    Efter triggertypen kommer en indikation på operationen för vilken triggern är definierad: INSERT, UPDATE eller DELETE.

    För en EFTER-utlösare kan du använda den för flera åtgärder samtidigt, till exempel UPPDATERA och INFOGA. I det här fallet indikeras operationer separerade med kommatecken. Du kan bara definiera en åtgärd för en ISTADEN FÖR utlösare.

    Och sedan efter ordet AS kommer en uppsättning SQL-uttryck, som faktiskt utgör kroppen av utlösaren.

    Låt oss skapa en trigger. Låt oss säga att vi har en databas productsdb med följande definition:

    SKAPA DATABAS productdb; GÅ ANVÄND productdb; SKAPA TABELL Produkter (Id INT IDENTITET PRIMÄRNYCKEL, Produktnamn NVARCHAR(30) NOT NULL, Tillverkare NVARCHAR(20) NOT NULL, ProductCount INT DEFAULT 0, Pris PENGAR INTE NULL);

    Låt oss definiera en utlösare som aktiveras när du lägger till och uppdaterar data:

    ANVÄND productdb; GÅ SKAPA TRIGGER Products_INSERT_UPDATE PÅ produkter EFTER INFOGA, UPPDATERA SOM UPPDATERING Produkter SET Pris = Pris + Pris * 0,38 WHERE Id = (VÄLJ ID FRÅN infogat)

    Låt oss säga att tabellen Produkter lagrar data om produkter. Men priset på en produkt innehåller ofta olika tillägg som mervärdesskatt, tillagd korruptionsskatt och så vidare. Personen som lägger till uppgifterna kanske inte känner till alla dessa finesser med skattebasen, och han bestämmer nettopriset. Med hjälp av en trigger kan vi justera priset på en produkt med ett visst belopp.

    På det här sättet kommer utlösaren att aktiveras vid alla INSERT- eller UPDATE-operationer i produkttabellen. Själva triggern kommer att ändra priset på produkten, och för att få produkten som har lagts till eller ändrats hittar vi denna produkt efter Id. Men vilket värde ska id:t för en sådan produkt ha? Faktum är att när du lägger till eller ändrar data, sparas det i den infogade mellantabellen. Den skapas automatiskt. Och från den kan vi få data om tillagda/ändrade produkter.

    Och efter att ha lagt till en produkt i produkttabellen kommer produkten i själva verket att ha ett något högre pris än det som fastställdes när det lades till:

    Ta bort en trigger

    För att ta bort en trigger måste du använda kommandot DROP TRIGGER:

    SLUTA TRIGGER Products_INSERT_UPDATE

    Inaktiverar en utlösare

    Det händer att vi vill pausa en utlösare, men vi vill inte ta bort den helt. I det här fallet kan den tillfälligt inaktiveras med kommandot DISABLE TRIGGER:

    INAKTIVERA TRIGGER Products_INSERT_UPDATE PÅ produkter

    Och när du behöver en trigger kan du aktivera den med kommandot ENABLE TRIGGER:

    AKTIVERA TRIGGER Products_INSERT_UPDATE PÅ produkter

    trigger:

    <Определение_триггера>::= (SKAPA | ÄNDRA) TRIGGER trigger_name PÅ (tabellnamn | visningsnamn) ( ( ( FÖR | EFTER | I STÄLLET FÖR ) ( [ DELETE] [,] [ INFOGA] [,] [ UPPDATERA] ) [ MED BILAGA ] [ INTE FÖR REPLICATION ] AS sql_statement[...n] ) | ( (FÖR | EFTER | I STÄLLET FÖR ) ( [,] ) [ MED BILAGA] [ INTE FÖR REPLICERING] SOM ( OM UPPDATERING(kolumnnamn) [ (OCH | ELLER) UPPDATERING( kolumnnamn)] [...n] |. IF (COLUMNS_UPDATES() (process_bit_operator) change_bit_mask) (comparison_bit_operator) bit_mask [...n]) sql_operator [...n] )

    En trigger kan bara skapas i den aktuella databasen, men det är möjligt att komma åt andra databaser inom triggern, inklusive de som finns på en fjärrserver.

    Låt oss titta på syftet med argumenten från CREATE | ALTER TRIGGER.

    Triggernamnet måste vara unikt i databasen. Dessutom kan du ange ägarens namn.

    När du anger argumentet WITH ENCRYPTION krypterar servern triggerkoden så att ingen, inklusive en administratör, kan komma åt eller läsa den. Kryptering används ofta för att dölja proprietära databehandlingsalgoritmer som är programmerarens immateriella rättigheter eller en affärshemlighet.

    Triggertyper

    Det finns två alternativ i SQL Server som bestämmer beteendet hos utlösare:

    • EFTER. Utlösaren exekveras efter att de kommandon som anropade den har slutförts. Om kommandona av någon anledning inte kan slutföras framgångsrikt, exekveras inte triggern. Det bör noteras att dataändringar som ett resultat av exekvering av en användarbegäran och triggerexekvering utförs i kroppen av en transaktion: om triggern rullas tillbaka, kommer användarändringar också att avvisas. Du kan definiera flera EFTER-utlösare för varje operation (INSERT, UPDATE, DELETE). Om du har flera AFTER-utlösare på en tabell kan du använda sp_settriggerorder-systemets lagrade procedur för att ange vilken utlösare som ska köras först och vilken som körs sist. Som standard, i SQL Server, är alla utlösare AFTER-utlösare.
    • ISTÄLLET FÖR . Utlösaren anropas istället för att utföra kommandon. Till skillnad från AFTER-utlösaren kan INSTEAD OF-utlösaren definieras för både en tabell och en vy. För varje INSERT-, UPDATE-, DELETE-operation kan endast en INSTEAD OF-utlösare definieras.

    Triggers kännetecknas av den typ av kommandon som de svarar på.

    Det finns tre typer av triggers:

    • INSERT TRIGGER – Utlöses när ett försök görs att infoga data med kommandot INSERT.
    • UPDATE TRIGGER – utlöses när ett försök görs att ändra data med kommandot UPDATE.
    • DELETE TRIGGER – utlöses när ett försök görs att radera data med kommandot DELETE.

    Konstruktioner [ DELETE] [,] [ INFOGA] [,] [ UPPDATERA] Och FÖR | EFTER | ISTÄLLET FÖR ) ([,] avgöra vilket kommando utlösaren ska svara på. När du skapar den måste minst ett kommando anges. Tillåten skapa en trigger, svarar på två eller alla tre kommandon.

    WITH APPEND låter dig skapa flera triggers av varje typ.

    skapa en trigger med argumentet INTE FÖR REPLIKATION är det förbjudet att köras medan tabeller modifieras av replikeringsmekanismer.

    AS sql_operator[...n]-konstruktionen definierar en uppsättning SQL-satser och kommandon som kommer att exekveras när triggern startas.

    Observera att ett antal operationer inte är tillåtna i en utlösare, till exempel:

    • skapa, modifiera och ta bort en databas;
    • återställa en säkerhetskopia av en databas eller transaktionslogg.

    Dessa kommandon tillåts inte att utföras eftersom de inte kan återställas om transaktionen där triggern utförs återställs. Det är osannolikt att detta förbud på något sätt påverkar funktionen hos skapade triggers. Det är svårt att hitta en situation där du till exempel efter att ha ändrat en tabellrad skulle behöva återställa en säkerhetskopia av transaktionsloggen.

    Trigger programmering

    När du kör kommandon för att lägga till, ändra och ta bort poster skapar servern två specialtabeller: insatt Och raderade. De innehåller listor över rader som kommer att infogas eller raderas när transaktionen är klar. Strukturen för de infogade och borttagna tabellerna är identisk med strukturen för de tabeller för vilka utlösaren är definierad. Varje utlösare skapar sin egen uppsättning infogade och borttagna tabeller, så ingen annan utlösare kan komma åt dem. Beroende på vilken typ av operation som fick utlösaren att köra, kan innehållet i de infogade och borttagna tabellerna vara olika:

    • INSERT kommando – den infogade tabellen innehåller alla rader som användaren försöker infoga i tabellen; det kommer inte att finnas en enda rad i den raderade tabellen; efter att triggern är klar kommer alla rader från den infogade tabellen att flyttas till källtabellen;
    • DELETE kommando – den raderade tabellen kommer att innehålla alla rader som användaren försöker ta bort; utlösaren kan kontrollera varje rad och avgöra om den är tillåten att raderas; det kommer inte att finnas några rader i den infogade tabellen;
    • UPDATE-kommandot - när det körs innehåller den raderade tabellen gamla radvärden som kommer att raderas efter framgångsrikt slutförande