“Trigger oder nicht Trigger. Das ist hier die Frage.”, wäre wohl die Aussage von Hamlet gewesen, hätte er sich mit Datenbankentwicklung und nicht mit anderen Tragödien beschäftigt. Eine Entscheidung für oder gegen Trigger ist selten unstrittig. Die IT-Branche ist nicht gerade arm, was Grundsatzdiskussionen und Glaubenskriege angeht. Und so hat auch die Datenbankentwicklung ein immer wiederkehrendes Thema: Pro und Contra Trigger. Dies soll nun kein einsamer Monolog für oder gegen Trigger werden, sondern die grundsätzliche Funktionsweise von Triggern erklären und Ihnen einige Informationen liefern, auf deren Grundlage Sie Ihre eigene Meinung bilden können.
Trigger können wie gespeicherte Prozeduren mehrere SQL-Anweisungen enthalten und werden als Objekt zur wiederverwendbaren Ausführung im SQL Server gespeichert. Wie auch bei einer gespeicherten Prozedur wird für einen Trigger bei der ersten Ausführung ein Ausführungsplan erstellt und im Prozedurcache abgelegt. Bei der nächsten Ausführung entfällt die Erstellung des Ausführungsplans, da der im Prozedurcache gespeicherte wiederverwendet werden kann. Insofern nutzen Trigger dieselben Performancevorteile wie gespeicherte Prozeduren.
Hier enden bereits die Gemeinsamkeiten von gespeicherten Prozeduren und Triggern, denn im Gegensatz zu gespeicherten Prozeduren sind Trigger keine eigenständigen Objekte und können nicht manuell aufgerufen werden. Vielmehr werden die im Trigger gespeicherten SQL-Anweisungen als fester Bestandteil einer Tabelle gespeichert.
Einsatzmöglichkeiten von Triggern
Ein Trigger ist immer an eine Tabelle gebunden und wird nur über eine Datenmanipulation – ein Update, ein Insert oder ein Delete – an dieser Tabelle ausgelöst.
Durch diesen Automatismus eignen Trigger sich besonders zur Gewährleistung der Datenkonsistenz und der Einhaltung von Geschäftsregeln.
Nachfolgend einige Beispiele für den Einsatz von Triggern:
- Durchsetzen der referentiellen Integrität: Der SQL Server bietet für die Einhaltung der referentiellen Integrität inklusive der Lösch- und Aktualisierungsweitergabe zwar bereits Standard-Funktionen, jedoch sind diese meist statisch und nicht flexibel.
- Mit einem Trigger können Sie die Prüfung der referentiellen Integrität beziehungsweise der Lösch- und Aktualisierungsweitergabe mit einer flexibleren Funktionalität erweitern und dadurch Datenmanipulationen zulassen, die die normalen Prüfungen eigentlich ausschließen.
- Generieren von komplexen Standardwerten: Im SQL Server können Sie zu jeder Spalte einer Tabelle einen Standardwert definieren. Dieser Wert ist entweder eine Konstante oder er wird mit T-SQL-Funktionen wie getdate() erzeugt.
- Sofern komplexere Standardwerte wie Berechnungen oder Werte aus anderen Tabellen benötigt werden, können diese durch Trigger berechnet beziehungsweise ermittelt werden.
- Einhalten von Regeln bei der Datenverarbeitung: Die Verarbeitung der Daten einer Datenbank unterliegen den Geschäftsregeln und den Regeln zur Datenkonsistenz. Um eine Datenmanipulation zu verhindern, die gegen diese Regeln verstieße, bieten Tabellen die Check Constraints (zu deutsch Einschränkungen). Die Möglichkeiten für Einschränkungen sind aber stark begrenzt, denn zur Prüfung der Eingabe stehen nur die in den Einschränkungen angegebenen Werte und einige wenige T-SQL-Funktionen zur Verfügung. Mit Triggern können die Eingaben flexibler geprüft werden, indem etwa die Eingaben mit Werten aus anderen Tabellen oder aus komplexen Berechnungen verglichen werden.
- Protokollierung von Datenänderungen: Die klassische Anforderung, dass jeder geänderte, gelöschte oder hinzugefügte Datensatz primärer Tabellen in einer anderen Tabelle protokolliert wird, lässt sich mit Triggern umsetzen.
- Redundante Datenhaltung: Redundante Daten werden gerne zur Performance-Steigerung verwendet. Um zum Beispiel die Rechnungssumme schneller zu ermitteln, könnten Sie diese im Rechnungskopf speichern. Die Summe wird anhand der Positionssummen der Rechnung ermittelt. Sofern sich an den Positionen etwas ändert, muss auch die Summe im Rechnungskopf angepasst werden. Wenn aber Redundanz, dann sollte diese schon korrekt und konsistent sein. Diese Konsistenz kann durch einen Trigger sichergestellt werden. Egal ob eine neue Position hinzugefügt, eine bestehende geändert oder gelöscht wird, der Trigger übernimmt die Übertragung der neuen Summe in den Rechnungskopf.
Dies sind nur ein paar Beispiele für den Einsatz von Triggern. Dadurch, dass Sie bis auf wenige Ausnahmen dieselben Möglichkeiten wie bei gespeicherten Prozeduren haben, können Sie mit Triggern sehr viel Logik abbilden. Um einen Trigger zu verwenden, muss dieser zunächst programmiert werden. Wie bereits erwähnt, wird ein Trigger immer dann ausgeführt, wenn an einer Tabelle Daten manipuliert wurden. Aus diesem Grund ist der Quellcode eines Triggers immer fest mit einer Tabelle verbunden.
Elemente eines Triggers
Zu einem Trigger gehört nicht nur die Angabe der Tabelle, sondern auch die Aktion der Datenmanipulation. Ein Trigger reagiert nicht zwangsläufig bei allen Datenmanipulationen, sondern auf solche, für die er auch definiert wurde.
Dabei kann der Trigger nur für eine der drei Aktionen Insert, Delete, Update oder für eine Kombination der drei aktiv werden. Die automatische Ausführung (im Fachjargon “das Feuern”) des Triggers ist nur bei diesen drei Aktionen möglich. Für andere Aktionen der Tabelle, wie Truncate Table, kann kein Trigger definiert werden.
Einer Tabelle können mehrere Trigger anhaften. Es können mehrere Aktionen in einem Trigger behandelt, pro Aktion ein einzelner Trigger und auch mehrere Trigger für eine einzelne Aktion erstellt werden. Es wäre also etwa möglich, für eine Tabelle einen Trigger zu definieren, der nur auf die Aktion Delete reagiert, und noch einen Trigger, der die Aktionen Insert und Update behandelt. Hinzu käme noch ein Trigger für einen besonderen Fall einer Update-Anweisung, der speziell nur dafür eingesetzt wird.
Sofern Sie für eine Aktion mehrere Trigger definiert haben, müssen Sie zusätzlich noch die Reihenfolge der Ausführung der Trigger mit der Systemprozedur sp_settriggerorder festlegen.
Der Trigger selbst enthält verschiedene Prüfungen und Anweisungen. Diese Prüfungen und Anweisungen programmieren Sie in T-SQL. Im Großen und Ganzen kann man die Entwicklung von Triggern mit der Entwicklung von gespeicherten Prozeduren vergleichen. Bei der Programmierung muss jedoch beachtet werden, dass die SQL-Anweisungen immer pro Aktion der Datenmanipulation ausgeführt werden. Insofern sollten auch alle betroffenen Datensätze der Datenmanipulation im Trigger angesprochen werden.
Diese Datensätze stehen innerhalb des Triggers in den virtuellen Tabellen inserted und deleted zur Verfügung. Beide Tabellen besitzen dieselbe Struktur wie die Tabelle des Triggers. Die Tabelle inserted beinhaltet die neuen Datensätze, die durch eine INSERT-Anweisung der Tabelle hinzugefügt wurden, während die Tabelle deleted die durch eine DELETE-Anweisung gelöschten Datensätze enthält. Die UPDATE-Anweisung nutzt beide Tabellen: die Werte vor der änderung stehen in der Tabelle deleted und die Werte nach der änderung in der Tabelle inserted.
Beide Tabellen können innerhalb des Triggers wie SQL Server-Tabellen verwendet werden. Sie können die Daten der Tabellen aggregieren, filtern, sortieren und die Tabellen mit anderen Tabellen verknüpfen und vieles mehr. Nur ändern können Sie die Daten dieser Tabellen nicht.
Trigger sind neben gespeicherten Prozeduren die einzigen SQL Server-Objekte, mit denen Daten manipuliert werden können. Es ist also möglich, in einem Trigger selbst wieder die Befehle Update, Delete und Insert zu verwenden.
Diese können Sie in der Tabelle des Triggers wie auch in anderen Tabellen ausführen. Sie sollten aber bedenken, dass durch diese Datenmanipulationen ebenfalls wieder Trigger ausgelöst werden können, die wiederum durch eigene Datenmanipulationen Trigger auslösen können.
Schließlich ist es sogar möglich, dass der Trigger, der die Datenmanipulation ausführt, durch weitere Trigger nochmals ausgelöst wird. Solche rekursiven Aufrufe sind in einer Tiefe von bis zu 32 Ebenen möglich. Diese Rekursivität wird nicht standardmäßig unterstützt, sondern muss in den Optionen der Datenbank erst aktiviert werden.
Mit Triggern können Sie die manipulierten Daten prüfen und je nach Ergebnis der Prüfung die Manipulation auch verhindern. Um dies dem Benutzer gegenüber transparent zu gestalten, können Sie aus einem Trigger heraus Meldungen ausgeben.
Neben der Ausgabe von Meldungen kann ein Trigger auch noch Daten ausgeben. Was auf den ersten Blick vielleicht selbstverständlich klingt, ist auf den zweiten eher fragwürdig. Denn welche Daten sollte ein Trigger liefern und, vor allem, wohin? Schließlich wird der Trigger bei einer Datenmanipulation an einer Tabelle automatisch ausgeführt und nicht im direkten Kontext einer manuellen Ausführung oder über ein Frontend. Ein wichtiger Punkt wurde bisher noch nicht erwähnt: Der SQL Server bietet zwei Arten von Triggern – den AFTER-Trigger und den INSTEAD OF-Trigger.
AFTER-Trigger
Ein AFTER-Trigger – früher auch als FOR-Trigger bekannt – wird erst nach der Datenmanipulation ausgelöst. Die im Trigger gespeicherten SQL-Anweisungen ergänzen somit die eigentliche Datenmanipulation.
Doch bis zur Ausführung des AFTER-Triggers ist es erst einmal ein weiter Weg. Der Vorgang einer Datenmanipulation teilt sich in mehrere Schritte:
- Die Tabellen inserted und deleted werden erstellt und mit den geänderten, gelöschten oder neu hinzugefügten Daten gefüllt.
- Der INSTEAD OF-Trigger der Tabelle wird ausgeführt, sofern ein solcher definiert ist. Je nach Ergebnis eines INSTEAD OF-Triggers wird die Eingabe abgewiesen und verhindert oder es wird mit den nächsten Schritten der Datenmanipulation fortgefahren.
- Die Prüfungen der Einschränkungen werden durchgeführt. Auch hier kann die Datenmanipulation bereits abgebrochen werden.
- Die referentielle Integrität wird geprüft: Noch ein Schritt, bei dem die Datenmanipulation vorzeitig beendet werden kann.
- Die Daten werden geändert.
- Der AFTER-Trigger wird ausgeführt. Sollten bei der Ausführung des AFTER-Triggers Fehler auftreten, wird die komplette Datenmanipulation verhindert und der Datensatz auf den Zustand vor der Aktion zurückgesetzt.
Ein AFTER-Trigger wird also nicht immer zwangsläufig ausgeführt, denn dazu ist die erfolgreiche Verarbeitung der eigentlichen Datenmanipulation eine unabdingbare Voraussetzung. Dadurch ist der AFTER-Trigger – wie der Name schon sagt – prädestiniert für Aktionen, die nach der vorhergehenden Datenmanipulation folgen müssen.
Mögliche Funktionen von AFTER-Triggern wären etwa die Protokollierung von Datenänderungen oder die Gewährleistung der Datenkonsistenz bei redundanter Datenhaltung, da hier nach der eigentlichen Datenmanipulation eine weitere ausgeführt wird.
Ein INSTEAD OF-Trigger hingegen greift vor der eigentlichen Datenmanipulation ein und ist eher für die Vermeidung oder Korrektur einer solchen zuständig.
INSTEAD OF-Trigger
Während der AFTER-Trigger am Ende der einzelnen Schritte einer Datenmanipulation steht, folgt der INSTEAD OF-Trigger als zweiter Schritt direkt hinter der Erstellung der Tabellen inserted und deleted.
Dies ist notwendig für die grundsätzlichen Aufgaben eines INSTEAD OF-Triggers: Das Prüfen der Datenmanipulation und das damit verbundene Verhindern der Aktion oder das Ersetzen der Werte durch andere, korrekte Werte. Insofern ist ein INSTEAD OF-Trigger optimal für die Prüfung von Dateneingaben, das Durchsetzen der referentiellen Integrität, das Erstellen von komplexen Standardwerten oder die Prüfung von aufwendigen Einschränkungen.
Ein INSTEAD OF-Trigger erweitert also nicht den Vorgang der eigentlichen Datenmanipulation, sondern ersetzt diesen durch seine eigenen SQL-Anweisungen. Für die Datenmanipulation ist nun nicht mehr die eigentliche Aktion mitsamt den dort geänderten Daten maßgebend, sondern die SQL-Anweisungen im INSTEAD OF-Trigger.
Im Gegensatz zu einem AFTER-Trigger können Sie pro Update, Delete oder Insert nur einen INSTEAD OF-Trigger definieren. Neben dem Ausführungszeitpunkt ist dies auch schon der einzige Unterschied zum AFTER-Trigger. Die Entwicklung beider Typen ist identisch.