Triggerek A megszorítások által kért ellenrzést a rendszer akkor hajtja végre, ha az adat, melyre a megszorítás vonatkozik megváltozik. (SQL2) Az SQL3 további lehetségeket ad az adatbázisba tárolásra kerül adatok helyességének az ellenrzésére. Ezek közül a triggerek már sok kereskedelmi rendszerben meg is vannak valósítva, pl. Oracle, MS SQL Server. A trigger szó jelentése: elsüt, kivált.
A triggerek tárolt eljárások, melyek elsüt események hatására indulnak. Ilyen elsüt esemény lehet egy táblára vonatkozó INSERT parancs DELETE parancs UPDATE parancs. Az ABKR felismeri az adott helyzeteket és meghívja a triggert. Egy trigger mindig egy táblára vonatkozik. Azokat az adatbázisokat, melyekben triggerek is implementálva vannak aktív adatbázisoknak nevezzük.
Trigger 3 részbl áll esemény (event) egy táblára vonatkozó beszúrás, törlés vagy módosítás. feltétel (condition) a triggert végrehajtja a rendszer, ha a feltétel igaz. Ha a megadott feltétel nem igaz, nem történik semmi a triggerrel összefüggésben. mvelet (action) egy eljárás, melyet végrehajt a rendszer amikor a trigger aktiválva van és a feltétel igaz.
a mvelet akár megakadályozhatja a kiváltó esemény megtörténtét vagy meg nem történtté teheti azt (pl. kitörölheti az épp felvitt sorokat); a trigger mvelet része hivatkozhat a triggert kiváltó parancs által módosított sorok régi és új értékeire, végrehajthat új lekérdezéseket, változtathatja az adatbázist. végrehajthat adatdefiníciós parancsokat (új táblákat hozhat létre, megváltoztathatja a hozzáférési jogokat).
A triggerek segítségével megoldható feladatok: automatikusan generálhatók származtatott oszlop értékek; hivatkozási épség megszorítások osztott adatbázis esetén; komplex logikai összefüggések programozhatók; átlátszóan megoldható az események naplózása; másolt táblák osztott adatbázisok esetén megoldhatók; statisztikákat készíthetünk a táblához való hozzáférésrl; triggerek segíthetnek a biztonság ellenrzésében, bejegyezni egy táblába ki milyen táblákon végzett valamilyen mveletet.
A trigger számos lehetséget kínál a programozónak: a mveletet végrehajthatjuk a kiváltó esemény eltt (BEFORE), után (AFTER) vagy helyette (INSTEAD OF); INSERT trigger mvelete hivatkozhat a mveletet kiváltó esemény által beszúrt sorok új értékeire; DELETE trigger mvelete hivatkozhat a törölt sorok régi értékeire; UPDATE trigger mvelete hivatkozhat a törölt sorok módosított sorok régi és új értékeire;
ha az esemény módosítás, akkor megadhatunk egy bizonyos oszlopot vagy oszlopokat, amelyre az esemény vonatkozik; a WHEN záradékban megadhatuk egy feltételt, és a mveletet csak akkor hajtja végre a rendszer, ha a trigger aktívvá válik és a kiváltó esemény bekövetkezésekor a feltétel igaz; a programozó megadhatja, hogy a mvelet végrehajtása o minden módosított sorra egyszer (FOR EACH ROW); o egy adatbázis-mvelet által módosított összes sorra vonatkozóan egyszer történjen (alapértelmezés szerint);
Példa: egy SQL3 szintaxissal megírt triggerre: CREATE TRIGGER Részl9Trigger AFTER UPDATE OF Fizetés ON Alkalmazottak REFERENCING OLD AS Régi, NEW AS Uj WHEN (Régi.Fizetés > Uj.Fizetés and Uj.RészlegID = 9) UPDATE Alkalmazottak SET Fizetés = Régi.Fizetés WHERE SzemSzám = Uj.SzemSzám FOR EACH ROW
különbség az utasítás szint és sor szint triggerek között akkor látszik, ha egy kiváltó esemény több sorra is vonatkozik példa: UPDATE mvelet egy tábla több sorát is módosítja, nem csak egyet. az utasítás szint trigger csak egyszer kerül végrehajtásra hivatkozni tudunk a módosítás eltti értékekre a régi sorok halmazának (OLD_TABLE) a segítségével; a módosítás utáni értékekre, az új sorok halmazával (NEW_TABLE).
Ha trigger sor szint, akkor a trigger mvelet része minden sorra végrehajtódik. ha a kiváltó esemény beszúrás, akkor a beszúrt sornak a NEW AS záradék segítségével adhatunk nevet. törlés esetén az OLD AS záradék segítségével nevezhetjük el a törölt sort. ha a kiváltó esemény a módosítás, a rendszer a módosítás eltti sort tekinti régi sornak, a módosítás utánit pedig újnak.
Az utasítás szint trigger hasznos, ha a trigger mvelet része nem függ a kiváltó esemény által érintett sorok értékeitl, Példa: biztonsági ellenrzés az aktuális felhasználóra vonatkozóan. generál egy sort a kiváltó eseményre vonatkozóan. példa Utasítás szint trigger SQL3-ban:
CREATE TRIGGER set_count AFTER INSERT ON Diakok /*event*/ REFERENCING NEW TABLE AS InsertedTuples FOR EACH STATEMENT INSERT INTO StatisticTable(ModifiedTable, ModificationType, Count) SELECT Diakok, Insert, count (*) FROM InsertedTuples I WHERE I.age <18
Egy trigger lehet: Sor szint és kiváltó esemény eltt kerül végrehajtásra, amikor is mieltt módosítaná a kiváltó esemény által érintett sorokat és mieltt ellenrizné az összes helyességi megszorítást, végrehajtja a trigger mvelet részét, ha a trigger feltétel része igaz. Utasítás szint és kiváltó esemény eltt kerül végrehajtásra. Ebben az esetben mieltt végrehajtaná a triggert kiváltó eseményt, végrehajtja a trigger mveletét.
Sor szint és kiváltó esemény után kerül végrehajtásra. Miután módosítja a kiváltó esemény által érintett sorokat és ellenrzi a helyességi megszorításokat, végrehajtja a trigger mvelet részét az aktuális sorra, ha a feltétel igaz. Ellentétben a BEFORE triggerekkel, az AFTER trigger esetén a rendszer lezárja a sorokat. (Lásd lezárás a fejezetben) Utasítás szint és kiváltó esemény után kerül végrehajtásra. Ebben az esetben a kiváltó esemény után ellenrzi a helyességi megszorításokat, majd végrehajtja a trigger mveleti részét.
Triggerek tervezése A trigger egy ers mehanizmus, hogy az adatbázisban végzett módosításokat könnyebben tudjuk feldolgozni, de elvigyázatosan kell használni ket. Triggerek halmazának a hatása lehet nagyon komplex, egy aktív adatbázis karbantartása nehézzé válhat. Ha egy parancs egynél több trigger-t aktivál, az ABKR mindegyiket végrehajtja, tetszleges sorrendben. Sokszor nem tudhatjuk, a trigger mely program mellékhatásaként lett végrehajtva.
Fontos, hogy egy trigger mvelet része aktiválhat egy másik triggert. Sajátos esetben elfordulhat, hogy ismét aktiválja az elz triggert ezeket rekurzív triggereknek nevezik. Az ilyen lánc aktiválásakor mivel nem tudjuk, hogy az ABKR milyen sorrendben hajtja ket végre, nehezen lehet eldönteni, hogy mi lesz az összhatásuk.
A triggerek tervezése esetén vegyük figyelembe a következ irányelveket: Ne írjunk triggereket olyan tevékenységre, melyre a megszorítások adnak lehetséget. (például hivatkozási épség megszorítás). Korlátozzuk a triggert legfeljebb 60 sorra. Ha több mveletre is szükségünk van, helyezzük azokat egy tárolt eljárásba és hívjuk meg a triggerbl a tárolt eljárást. Ne tervezzünk rekurzív triggereket.
Használjuk mértékkel a triggereket, gondoljunk arra, hogy minden egyes adatkezelési mvelet esetén meghívásra kerülnek, és nagyon sok munkát igényelhetnek. Csak olyan mveletek elvégzésére használjuk, azaz a globális mveletekre, melyek minden felhasználó esetében szükségesek.
Megszorítások triggerekkel szemben: Triggereket is azért találták ki, hogy az adatbázis konzisztens maradjon. A helyességi megszorításokat úgyszintén, viszont ezek nem mveletként vannak értelmezve, ellentétben a triggerekkel, így könnyebb megérteni a helyességi megszorításokat. A helyességi megszorítások megvédik az adatot mindenféle parancs esetén, hogy ne kerüljenek inkonzisztens állapotba, de triggereket csak speciális parancsok aktiválnak (INSERT, DELETE, UPDATE).
A triggerek rugalmasabb úton tartják meg az adatbázis integritását. Példák triggerekre MS SQL Server-ben új sorra az inserted kulcsszóval hivatkozhatunk törölt sorokra a deleted kulcsszóval lehet hivatkozni UPDATE úgy történik, hogy kitörli a módosított sorokat (vagy csak egy sort) és beszúrja az új sort, ezért lehet hivatkozni az inserted és deleted sorokra is.
Példa Egy software cég projektjeinek a tárolása esetén érdekeltek vagyunk a megrendel cég (tárolva a Customers táblában), illetve a rendelt projekt (tárolva a Projects táblában) adataiban. Egy projekt különböz állapotban lehet: tervezett, aktív, megszakítva, befejezett, stb. (tárolva a ProjStates relációban). Egy projektet felosztunk több kiszabott feladatra (Tasks), melyet egy alkalmazott (Employee) kell elvégezzen, több napra is kiterjedhet egy feladat.
Egy feladatot apró tevékenységekre osztunk, melyet ugyanaz az alkalmazott végez, mint a feladatot, és nem terjedhet több napra, csak egyre. A projektnek, feladatnak és tevékenységnek is vannak: o tervezett kezdési dátum (PlannedStartDate), o effektív kezdési dátum (RealStartDate), o tervezett befejezési dátum (PlannedEndDate), o effektív befejezési dátum (RealEndDate). A projekt, feladat és tevékenység lehet befejezett vagy nem. A Tasks és Activities relációk esetén a Finished (1 ha befejezett, 0 ha nem befejezett) mez adja ezt meg, a
Projects esetén pedig a ProjStateID (4-es ID a befejezett terv). Customers [CustomerID, Name, Address, ] Projects [ProjectID, Title, CustomerID, ProjManID, ProjStateID, PlannedStartDate, PlannedEndDate, RealStartDate,RealEndDate, ] Employees [EmployeeID, FirstName, LastName, ] Tasks [TaskID, Name, ProjectID, Finished, EmployeeID,PlannedStartDate, PlannedEndDate, RealStartDate, RealEndDate, ]
Activities [ActivID, Text, TaskID, Finished, PlannedStartDate, PlannedEndDate, RealStartDate, RealEndDate, ] ProjStates [ProjStateID, Name] A feladatok amit a triggerek segítségével szeretnénk megoldani a következk: helyességi feltételek ellenrzése: nem lehet egy projekt befejezett állapotban, ha létezik olyan a projekthez tartozó feladat, mely nincs befejezve; (lásd Proj_upd trigger)
CREATE TRIGGER Proj_upd ON Projects FOR UPDATE AS declare @vprojid int, @vprojstid as int /* Tests if the ProjStateID is modified to be finished, if there are some tasks belonging to the project, which has Finished on 0 */ set nocount on select @vprojstid = i.projstateid, @vprojid =i.projectid from inserted i
if @vprojstid = 4 begin if exists (select TaskID from Tasks where ProjectID = @vprojid and Finished = 0) begin raiserror ('There are tasks belonging to the project, which are not finished.',16,1) ROLLBACK TRANSACTION end end set nocount off
nem lehet egy feladat befejezett állapotban, ha létezik olyan a feladathoz tartozó tevékenység, mely nincs befejezve. ha egy feladat Finished mezjét 0-ra módosítjuk, azt jelenti azeltt befejezett volt és most be nem fejezetté módosítjuk, elfordulhat, hogy már a projekt is befejezettnek lett nyilvánítva és ha megengedjük, hogy a feladatot be nem fejezetté módosítsa a felhasználó, akkor olyan állapotba jut az adatbázis, hogy a projekt be van fejezve, de van egy feladat, mely hozzá tartozik és nincs befejezve; (lásd Task_upd)
CREATE TRIGGER Task_upd ON Tasks FOR INSERT, UPDATE AS declare @task_finished tinyint, @vtaskid int, @vfinished tinyint, @vprojid int, @proj_state int /* Tests if the Finished field is modified to 1, if there are some activities belonging to the task, which has Finished on 0 */ set nocount on select @task_finished = i.finished, @vtaskid=i.taskid, @vprojid = i.projectid from inserted i
if @task_finished = 1 begin if exists (select ActivID from Activities where TaskID = @vtaskid and Finished = 0) begin raiserror ('There are activities belonging to the task, which are not finished.',16,1) ROLLBACK TRANSACTION end end
/* Tests if the Finished field is modified to 0, the project which it belongs has been marked Finished (ProjStateID= 4) */ if @task_finished = 0 begin select @proj_state = ProjStateID from Projects where ProjectID = @vprojid if @proj_state = 4 begin raiserror ('The project from which the task belongs was marked finished.',16,1) ROLLBACK TRANSACTION
end end set nocount off A Projects esetén csak UPDATE triggert írtunk, míg a Tasks esetén UPDATE és INSERT triggert. A Tasks esetén hivatkozási épség megszorítás van a ProjectID-re, ez azt jelenti, hogy nem tudunk feladatot begyjteni projekt eltt, elször léteznie kell egy projektnek és ahhoz gyjthetünk be feladatokat. Tehát INSERT esetén a projekthez még nem tartozhat egyetlen
feladat sem, nem áll fenn a helytelen állapot veszélye, mely módosítás esetén fennállhat. A feladat esetén, elfordulhat, hogy egy befejezett projekthez akarunk beszúrni egy új, be nem fejezett tevékenységet.