Die allgemeinste Konsistenzsicherung geschieht durch einen Trigger. Dies ist eine benutzerdefinierte Prozedur, die automatisch bei Erfüllung einer bestimmten Bedingung vom DBMS gestartet wird. Hilfreich sind zwei vom System gefüllte Tabellen DELETED und INSERTED, in der solche Zeilen gespeichert sind, auf die sich das beabsichtigte Löschen bzw. Einfügen beziehen. In diesem Zusammenhang ist die Operation UPDATE als hintereinander ausgeführte Kombination von Löschen und Einfügen zu sehen.
Listing 8.2 zeigt einen AFTER-UPDATE-Trigger für die Tabelle Professoren, der nach jedem Update aufgerufen wird und im Falle einer Degradierung diese wieder rückgängig macht.
create trigger korrigieredegradierung -- definiere einen Trigger on Professoren after update -- nach update von Professoren as if update(Rang) -- falls Rang veraendert wurde begin update professoren -- aendere Professoren erneut set rang = d.rang -- setze Rang auf alten Rang from professoren p, deleted d -- mit Hilfe der Tabelle deleted where p.persnr = d.persnr -- bei uebereinstimmender PersNr and p.rang < d.rang -- falls neuer Rang < alter Rang end |
Listing 8.3 zeigt die Lösung für dasselbe Problem durch einen INSTEAD-OF-UPDATE-Trigger, der statt des Update durchgeführt wird. Durch Vergleich der Einträge in den Systemtabellen DELETED und INSERTED kann die beabsichtigte Beförderung für solche Professoren durchgeführt werden, die zuvor noch keine Rangangabe aufwiesen oder eine kleinere Rangangabe hatten.
create trigger verhinderedegradierung -- definiere einen Trigger on Professoren instead of update -- statt eines updates as update professoren -- aendere nun Professoren doch set rang = i.rang -- setze auf eingefuegten Rang from deleted d, inserted i -- unter Verwendung von d und i where professoren.persnr = d.persnr -- bei passender Personalnummer and d.persnr = i.persnr -- bei passender Personalnummer and (d.rang=null -- falls vorher kein Rang vorhanden or d.rang < i.rang) -- oder alter Rang < neuer Rang |
Listing 8.4 zeigt einen AFTER-INSERT-Trigger, der immer nach dem Einfügen eines Tupels in die Tabelle hoeren einen Professor sucht, der jetzt mehr als 10 Hörer hat und ihn dann nach C4 befördert.
create trigger befoerderung -- definiere den Trigger befoerderung on hoeren after insert, update -- nach insert oder update bei hoeren as update professoren set rang='C4' -- befoerdere Professor nach C4 where persnr in -- falls seine Personalnummer in (select persnr -- der Menge der Personalnummern liegt from professoren p, -- die mehr als 10 Hoerer haben vorlesungen v, hoeren h where p.persnr = v.gelesenvon and v.vorlnr = h.vorlnr group by p.persnr having count(*) > 10) |
Listings 8.5 und 8.6 zeigen die Verwendung eines INSTEAD-OF-INSERT-Triggers im Zusammenhang mit Sichten, in die nur unter sehr eingeschränkten Bedingungen eingefügt werden kann. Auf der Tabelle Person sei eine Sicht Geburtstagsliste gegeben. In dieser Sicht wird das momentane Lebensalter in Jahren anhand der Systemzeit und des gespeicherten Geburtsdatums errechnet. Natürlich ist diese Sicht nicht update-fähig bei Einfügen eines Namens mit Lebensalter. Durch den Trigger geburtstag läßt sich das Einfügen trotzdem erreichen, da nach Umrechnung des Alters in ein Geburtsdatum ein Tupel in die Tabelle Person eingefügt werden kann.
create view Geburtstagsliste -- lege Sicht an as -- bestehend aus select Name, -- Name datediff(year,gebdatum,getdate()) as Jahre -- Lebensalter from Person -- von Tabelle Person |
create trigger Geburtstag -- lege Trigger an bzgl. on Geburtstagsliste -- Geburtstagsliste instead of insert -- statt einzufuegen as insert into Person (name,gebdatum) -- fuege in Person ein select i.name, -- eingefuegter Name dateadd(year, -i.jahre, getdate()) -- errechnetes Geburtsjahr from inserted i -- aus Tabelle inserted |
Das Schlüsselwort drop entfernt einen Trigger: drop trigger Geburtstag