{"id":55000636,"date":"2008-12-01T00:00:00","date_gmt":"2023-03-12T18:09:26","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=636"},"modified":"2024-02-19T08:24:08","modified_gmt":"2024-02-19T08:24:08","slug":"trigger","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/trigger\/","title":{"rendered":"Trigger"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg03.met.vgwort.de\/na\/3f273a18602a4f13a135811626535088\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>&#8222;Trigger oder nicht Trigger. Das ist hier die Frage.&#8220;, w&auml;re wohl die Aussage von Hamlet gewesen, h&auml;tte er sich mit Datenbankentwicklung und nicht mit anderen Trag&ouml;dien besch&auml;ftigt. Eine Entscheidung f&uuml;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&uuml;r oder gegen Trigger werden, sondern die grunds&auml;tzliche Funktionsweise von Triggern erkl&auml;ren und Ihnen einige Informationen liefern, auf deren Grundlage Sie Ihre eigene Meinung bilden k&ouml;nnen.<\/b><\/p>\n<p>Trigger k&ouml;nnen wie gespeicherte Prozeduren mehrere SQL-Anweisungen enthalten und werden als Objekt zur wiederverwendbaren Ausf&uuml;hrung im SQL Server gespeichert. Wie auch bei einer gespeicherten Prozedur wird f&uuml;r einen Trigger bei der ersten Ausf&uuml;hrung ein Ausf&uuml;hrungsplan erstellt und im Prozedurcache abgelegt. Bei der n&auml;chsten Ausf&uuml;hrung entf&auml;llt die Erstellung des Ausf&uuml;hrungsplans, da der im Prozedurcache gespeicherte wiederverwendet werden kann. Insofern nutzen Trigger dieselben Performancevorteile wie gespeicherte Prozeduren.<\/p>\n<p>Hier enden bereits die Gemeinsamkeiten von gespeicherten Prozeduren und Triggern, denn im Gegensatz zu gespeicherten Prozeduren sind Trigger keine eigenst&auml;ndigen Objekte und k&ouml;nnen nicht manuell aufgerufen werden. Vielmehr werden die im Trigger gespeicherten SQL-Anweisungen als fester Bestandteil einer Tabelle gespeichert.<\/p>\n<p class=\"zwischen-berschrift-oberer-spaltenrand\">Einsatzm&ouml;glichkeiten von Triggern<\/p>\n<p>Ein Trigger ist immer an eine Tabelle gebunden und wird nur &uuml;ber eine Datenmanipulation &#8211; ein <b>Update<\/b>, ein <b>Insert<\/b> oder ein <b>Delete<\/b> &#8211; an dieser Tabelle ausgel&ouml;st. <\/p>\n<p>Durch diesen Automatismus eignen Trigger sich besonders zur Gew&auml;hrleistung der Datenkonsistenz und der Einhaltung von Gesch&auml;ftsregeln. <\/p>\n<p>Nachfolgend einige Beispiele f&uuml;r den Einsatz von Triggern:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Durchsetzen der referentiellen Integrit&auml;t: Der SQL Server bietet f&uuml;r die Einhaltung der referentiellen Integrit&auml;t inklusive der L&ouml;sch- und Aktualisierungsweitergabe zwar bereits Standard-Funktionen, jedoch sind diese meist statisch und nicht flexibel.<\/li>\n<li class=\"aufz-hlung\">Mit einem Trigger k&ouml;nnen Sie die Pr&uuml;fung der referentiellen Integrit&auml;t beziehungsweise der L&ouml;sch- und Aktualisierungsweitergabe mit einer flexibleren Funktionalit&auml;t erweitern und dadurch Datenmanipulationen zulassen, die die normalen Pr&uuml;fungen eigentlich ausschlie&szlig;en.<\/li>\n<li class=\"aufz-hlung\">Generieren von komplexen Standardwerten: Im SQL Server k&ouml;nnen Sie zu jeder Spalte einer Tabelle einen Standardwert definieren. Dieser Wert ist entweder eine Konstante oder er wird mit T-SQL-Funktionen wie <b>getdate()<\/b> erzeugt.<\/li>\n<li class=\"aufz-hlung\">Sofern komplexere Standardwerte wie Berechnungen oder Werte aus anderen Tabellen ben&ouml;tigt werden, k&ouml;nnen diese durch Trigger berechnet beziehungsweise ermittelt werden.<\/li>\n<li class=\"aufz-hlung\">Einhalten von Regeln bei der Datenverarbeitung: Die Verarbeitung der Daten einer Datenbank unterliegen den Gesch&auml;ftsregeln und den Regeln zur Datenkonsistenz. Um eine Datenmanipulation zu verhindern, die gegen diese Regeln verstie&szlig;e, bieten Tabellen die <b>Check Constraints<\/b> (zu deutsch Einschr&auml;nkungen). Die M&ouml;glichkeiten f&uuml;r Einschr&auml;nkungen sind aber stark begrenzt, denn zur Pr&uuml;fung der Eingabe stehen nur die in den Einschr&auml;nkungen angegebenen Werte und einige wenige T-SQL-Funktionen zur Verf&uuml;gung. Mit Triggern k&ouml;nnen die Eingaben flexibler gepr&uuml;ft werden, indem etwa die Eingaben mit Werten aus anderen Tabellen oder aus komplexen Berechnungen verglichen werden.<\/li>\n<li class=\"aufz-hlung\">Protokollierung von Daten&auml;nderungen: Die klassische Anforderung, dass jeder ge&auml;nderte, gel&ouml;schte oder hinzugef&uuml;gte Datensatz prim&auml;rer Tabellen in einer anderen Tabelle protokolliert wird, l&auml;sst sich mit Triggern umsetzen.<\/li>\n<li class=\"aufz-hlung\">Redundante Datenhaltung: Redundante Daten werden gerne zur Performance-Steigerung verwendet. Um zum Beispiel die Rechnungssumme schneller zu ermitteln, k&ouml;nnten Sie diese im Rechnungskopf speichern. Die Summe wird anhand der Positionssummen der Rechnung ermittelt. Sofern sich an den Positionen etwas &auml;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&uuml;gt, eine bestehende ge&auml;ndert oder gel&ouml;scht wird, der Trigger &uuml;bernimmt die &Uuml;bertragung der neuen Summe in den Rechnungskopf.<\/li>\n<\/ul>\n<p>Dies sind nur ein paar Beispiele f&uuml;r den Einsatz von Triggern. Dadurch, dass Sie bis auf wenige Ausnahmen dieselben M&ouml;glichkeiten wie bei gespeicherten Prozeduren haben, k&ouml;nnen Sie mit Triggern sehr viel Logik abbilden. Um einen Trigger zu verwenden, muss dieser zun&auml;chst programmiert werden. Wie bereits erw&auml;hnt, wird ein Trigger immer dann ausgef&uuml;hrt, wenn an einer Tabelle Daten manipuliert wurden. Aus diesem Grund ist der Quellcode eines Triggers immer fest mit einer Tabelle verbunden.<\/p>\n<h2>Elemente eines Triggers<\/h2>\n<p>Zu einem Trigger geh&ouml;rt nicht nur die Angabe der Tabelle, sondern auch die Aktion der Datenmanipulation. Ein Trigger reagiert nicht zwangsl&auml;ufig bei allen Datenmanipulationen, sondern auf solche, f&uuml;r die er auch definiert wurde.<\/p>\n<p>Dabei kann der Trigger nur f&uuml;r eine der drei Aktionen Insert, Delete, Update oder f&uuml;r eine Kombination der drei aktiv werden. Die automatische Ausf&uuml;hrung (im Fachjargon &#8222;das Feuern&#8220;) des Triggers ist nur bei diesen drei Aktionen m&ouml;glich. F&uuml;r andere Aktionen der Tabelle, wie Truncate Table, kann kein Trigger definiert werden.<\/p>\n<p>Einer Tabelle k&ouml;nnen mehrere Trigger anhaften. Es k&ouml;nnen mehrere Aktionen in einem Trigger behandelt, pro Aktion ein einzelner Trigger und auch mehrere Trigger f&uuml;r eine einzelne Aktion erstellt werden. Es w&auml;re also etwa m&ouml;glich, f&uuml;r eine Tabelle einen Trigger zu definieren, der nur auf die Aktion <b>Delete <\/b>reagiert, und noch einen Trigger, der die Aktionen <b>Insert <\/b>und <b>Update <\/b>behandelt. Hinzu k&auml;me noch ein Trigger f&uuml;r einen besonderen Fall einer Update-Anweisung, der speziell nur daf&uuml;r eingesetzt wird. <\/p>\n<p>Sofern Sie f&uuml;r eine Aktion mehrere Trigger definiert haben, m&uuml;ssen Sie zus&auml;tzlich noch die Reihenfolge der Ausf&uuml;hrung der Trigger mit der Systemprozedur <b>sp_settriggerorder <\/b>festlegen.<\/p>\n<p>Der Trigger selbst enth&auml;lt verschiedene Pr&uuml;fungen und Anweisungen. Diese Pr&uuml;fungen und Anweisungen programmieren Sie in T-SQL. Im Gro&szlig;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&uuml;hrt werden. Insofern sollten auch alle betroffenen Datens&auml;tze der Datenmanipulation im Trigger angesprochen werden.<\/p>\n<p>Diese Datens&auml;tze stehen innerhalb des Triggers in den virtuellen Tabellen <b>inserted <\/b>und <b>deleted <\/b>zur Verf&uuml;gung. Beide Tabellen besitzen dieselbe Struktur wie die Tabelle des Triggers. Die Tabelle <b>inserted <\/b>beinhaltet die neuen Datens&auml;tze, die durch eine <b>INSERT<\/b>-Anweisung der Tabelle hinzugef&uuml;gt wurden, w&auml;hrend die Tabelle <b>deleted <\/b>die durch eine <b>DELETE<\/b>-Anweisung gel&ouml;schten Datens&auml;tze enth&auml;lt. Die <b>UPDATE<\/b>-Anweisung nutzt beide Tabellen: die Werte vor der &auml;nderung stehen in der Tabelle <b>deleted <\/b>und die Werte nach der &auml;nderung in der Tabelle <b>inserted<\/b>.<\/p>\n<p>Beide Tabellen k&ouml;nnen innerhalb des Triggers wie SQL Server-Tabellen verwendet werden. Sie k&ouml;nnen die Daten der Tabellen aggregieren, filtern, sortieren und die Tabellen mit anderen Tabellen verkn&uuml;pfen und vieles mehr. Nur &auml;ndern k&ouml;nnen Sie die Daten dieser Tabellen nicht.<\/p>\n<p>Trigger sind neben gespeicherten Prozeduren die einzigen SQL Server-Objekte, mit denen Daten manipuliert werden k&ouml;nnen. Es ist also m&ouml;glich, in einem Trigger selbst wieder die Befehle <b>Update<\/b>, <b>Delete <\/b>und <b>Insert <\/b>zu verwenden.<\/p>\n<p>Diese k&ouml;nnen Sie in der Tabelle des Triggers wie auch in anderen Tabellen ausf&uuml;hren. Sie sollten aber bedenken, dass durch diese Datenmanipulationen ebenfalls wieder Trigger ausgel&ouml;st werden k&ouml;nnen, die wiederum durch eigene Datenmanipulationen Trigger ausl&ouml;sen k&ouml;nnen.<\/p>\n<p>Schlie&szlig;lich ist es sogar m&ouml;glich, dass der Trigger, der die Datenmanipulation ausf&uuml;hrt, durch weitere Trigger nochmals ausgel&ouml;st wird. Solche rekursiven Aufrufe sind in einer Tiefe von bis zu 32 Ebenen m&ouml;glich. Diese Rekursivit&auml;t wird nicht standardm&auml;&szlig;ig unterst&uuml;tzt, sondern muss in den Optionen der Datenbank erst aktiviert werden.<\/p>\n<p>Mit Triggern k&ouml;nnen Sie die manipulierten Daten pr&uuml;fen und je nach Ergebnis der Pr&uuml;fung die Manipulation auch verhindern. Um dies dem Benutzer gegen&uuml;ber transparent zu gestalten, k&ouml;nnen Sie aus einem Trigger heraus Meldungen ausgeben. <\/p>\n<p>Neben der Ausgabe von Meldungen kann ein Trigger auch noch Daten ausgeben. Was auf den ersten Blick vielleicht selbstverst&auml;ndlich klingt, ist auf den zweiten eher fragw&uuml;rdig. Denn welche Daten sollte ein Trigger liefern und, vor allem, wohin? Schlie&szlig;lich wird der Trigger bei einer Datenmanipulation an einer Tabelle automatisch ausgef&uuml;hrt und nicht im direkten Kontext einer manuellen Ausf&uuml;hrung oder &uuml;ber ein Frontend. Ein wichtiger Punkt wurde bisher noch nicht erw&auml;hnt: Der SQL Server bietet zwei Arten von Triggern &#8211; den <b>AFTER<\/b>-Trigger und den <b>INSTEAD OF<\/b>-Trigger.<\/p>\n<h2>AFTER-Trigger<\/h2>\n<p>Ein <b>AFTER<\/b>-Trigger &#8211; fr&uuml;her auch als <b>FOR<\/b>-Trigger bekannt &#8211; wird erst nach der Datenmanipulation ausgel&ouml;st. Die im Trigger gespeicherten SQL-Anweisungen erg&auml;nzen somit die eigentliche Datenmanipulation.<\/p>\n<p>Doch bis zur Ausf&uuml;hrung des <b>AFTER<\/b>-Triggers ist es erst einmal ein weiter Weg. Der Vorgang einer Datenmanipulation teilt sich in mehrere Schritte:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Die Tabellen <b>inserted <\/b>und <b>deleted <\/b>werden erstellt und mit den ge&auml;nderten, gel&ouml;schten oder neu hinzugef&uuml;gten Daten gef&uuml;llt.<\/li>\n<li class=\"aufz-hlung\">Der <b>INSTEAD OF<\/b>-Trigger der Tabelle wird ausgef&uuml;hrt, sofern ein solcher definiert ist. Je nach Ergebnis eines <b>INSTEAD OF<\/b>-Triggers wird die Eingabe abgewiesen und verhindert oder es wird mit den n&auml;chsten Schritten der Datenmanipulation fortgefahren.<\/li>\n<li class=\"aufz-hlung\">Die Pr&uuml;fungen der Einschr&auml;nkungen werden durchgef&uuml;hrt. Auch hier kann die Datenmanipulation bereits abgebrochen werden.<\/li>\n<li class=\"aufz-hlung\">Die referentielle Integrit&auml;t wird gepr&uuml;ft: Noch ein Schritt, bei dem die Datenmanipulation vorzeitig beendet werden kann.<\/li>\n<li class=\"aufz-hlung\">Die Daten werden ge&auml;ndert.<\/li>\n<li class=\"aufz-hlung\">Der <b>AFTER<\/b>-Trigger wird ausgef&uuml;hrt. Sollten bei der Ausf&uuml;hrung des <b>AFTER<\/b>-Triggers Fehler auftreten, wird die komplette Datenmanipulation verhindert und der Datensatz auf den Zustand vor der Aktion zur&uuml;ckgesetzt.<\/li>\n<\/ul>\n<p>Ein <b>AFTER<\/b>-Trigger wird also nicht immer zwangsl&auml;ufig ausgef&uuml;hrt, denn dazu ist die erfolgreiche Verarbeitung der eigentlichen Datenmanipulation eine unabdingbare Voraussetzung. Dadurch ist der <b>AFTER<\/b>-Trigger &#8211; wie der Name schon sagt &#8211; pr&auml;destiniert f&uuml;r Aktionen, die nach der vorhergehenden Datenmanipulation folgen m&uuml;ssen.<\/p>\n<p>M&ouml;gliche Funktionen von <b>AFTER<\/b>-Triggern w&auml;ren etwa die Protokollierung von Daten&auml;nderungen oder die Gew&auml;hrleistung der Datenkonsistenz bei redundanter Datenhaltung, da hier nach der eigentlichen Datenmanipulation eine weitere ausgef&uuml;hrt wird.<\/p>\n<p>Ein <b>INSTEAD OF<\/b>-Trigger hingegen greift vor der eigentlichen Datenmanipulation ein und ist eher f&uuml;r die Vermeidung oder Korrektur einer solchen zust&auml;ndig.<\/p>\n<h2>INSTEAD OF-Trigger<\/h2>\n<p>W&auml;hrend der <b>AFTER<\/b>-Trigger am Ende der einzelnen Schritte einer Datenmanipulation steht, folgt der <b>INSTEAD OF<\/b>-Trigger als zweiter Schritt direkt hinter der Erstellung der Tabellen <b>inserted <\/b>und <b>deleted<\/b>.<\/p>\n<p>Dies ist notwendig f&uuml;r die grunds&auml;tzlichen Aufgaben eines <b>INSTEAD OF<\/b>-Triggers: Das Pr&uuml;fen der Datenmanipulation und das damit verbundene Verhindern der Aktion oder das Ersetzen der Werte durch andere, korrekte Werte. Insofern ist ein <b>INSTEAD OF<\/b>-Trigger optimal f&uuml;r die Pr&uuml;fung von Dateneingaben, das Durchsetzen der referentiellen Integrit&auml;t, das Erstellen von komplexen Standardwerten oder die Pr&uuml;fung von aufwendigen Einschr&auml;nkungen.<\/p>\n<p>Ein <b>INSTEAD OF<\/b>-Trigger erweitert also nicht den Vorgang der eigentlichen Datenmanipulation, sondern ersetzt diesen durch seine eigenen SQL-Anweisungen. F&uuml;r die Datenmanipulation ist nun nicht mehr die eigentliche Aktion mitsamt den dort ge&auml;nderten Daten ma&szlig;gebend, sondern die SQL-Anweisungen im <b>INSTEAD OF<\/b>-Trigger.<\/p>\n<p>Im Gegensatz zu einem <b>AFTER<\/b>-Trigger k&ouml;nnen Sie pro <b>Update<\/b>, <b>Delete <\/b>oder <b>Insert <\/b>nur einen <b>INSTEAD OF<\/b>-Trigger definieren. Neben dem Ausf&uuml;hrungszeitpunkt ist dies auch schon der einzige Unterschied zum <b>AFTER<\/b>-Trigger. Die Entwicklung beider Typen ist identisch.<\/p>\n<h2>Entwickeln eines Triggers<\/h2>\n<p>F&uuml;r die Schreiben eines Triggers kann das SQL Server Management Studio verwendet werden. Die Trigger einer Tabelle finden Sie unterhalb der jeweiligen Tabelle im Knoten <b>Trigger<\/b>. Dort sehen Sie im Kontextmen&uuml; auch den Eintrag <b>Neuer Trigger<\/b> zum Anlegen eines neuen Triggers (s. Abb. 1).<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2008_06\/Trigger-web-images\/Bild23428_opt.jpeg\" alt=\"missing image file\" \/><\/p>\n<p class=\"abbildungsunterschrift\">Abb. 1: Ein neuer Trigger<\/p>\n<p>Das SQL Server Management Studio bietet Ihnen zur Erstellung eines Triggers keinen Abfragedesigner. Wie schon bei den gespeicherten Prozeduren erhalten Sie lediglich ein neues Abfragefenster mit einer Skriptvorlage; in diesem Fall mit einer Vorlage zur Anlage eines neuen Triggers.<\/p>\n<p>Einen neuen Trigger legen Sie mit der Anweisung <b>CREATE TRIGGER <\/b>an. Dazu m&uuml;ssen Sie nicht nur den Namen des Triggers angeben, sondern mit der Option <b>ON <\/b>auch<b> <\/b>die Tabelle, an die dieser Trigger gebunden ist. Als weitere Voraussetzung m&uuml;ssen der Typ &#8211; <b>AFTER <\/b>oder <b>INSTEAD OF<\/b> -, sowie die Aktion(en) <b>Insert<\/b>, <b>Delete<\/b> oder <b>Update<\/b> angegeben werden.<\/p>\n<p>Anschlie&szlig;end wird die eigentliche Programmlogik durch <b>AS <\/b>eingeleitet und im <b>BEGIN&#8230;END<\/b>-Block zusammengefasst. Dort k&ouml;nnen Sie Ihren Ideen freien Lauf lassen, sofern diese nicht gegen die Regeln von T-SQL versto&szlig;en oder der Logik der Trigger-Entwicklung widersprechen.<\/p>\n<p>Den ersten T-SQL-Befehl in Ihrem Trigger bietet Ihnen die Vorlage auch schon direkt an: <b>SET NOCOUNT ON<\/b>. Sie sollten dieses Angebot unbedingt annehmen, da diese Anweisung die Ausgabe der Meldungen <b>xx rows affected<\/b> zu den <b>DONE_IN_PROC<\/b>-Anweisungen unterbindet. Access hat je nach Version und eingesetztem Treiber mit diesen R&uuml;ckmeldungen so seine Probleme. Doch dazu sp&auml;ter mehr.<\/p>\n<p>Als Erstes lernen Sie die Umsetzung eines klassischen <b>AFTER<\/b>-Triggers kennen: Die in der <b>Northwind<\/b>-Datenbank vergebenen Rabatte von 10 bis 25 Prozent bei den Bestellpositionen sollen in einer eigenen Tabelle protokolliert werden.<\/p>\n<p>Diese Tabelle wird den Abteilungsleitern als Grundlage zu Auswertungen dienen. Um ihnen die Auswertung etwas zu erleichtern, werden die Bestellnummer, Kundennummer, Artikelnummer, Einzelpreis, Menge und Rabatt, sowie die Mitarbeiter-ID des Verk&auml;ufers und die Mitarbeiter-ID des Vorgesetzten in der Tabelle protokolliert. <\/p>\n<p>Doch vorab ben&ouml;tigen Sie f&uuml;r dieses Beispiel noch die Tabelle zur Protokollierung der Daten. Listing 1 zeigt das <b>CREATE TABLE<\/b>-Skript, mit dem Sie diese Tabelle anlegen k&ouml;nnen.<\/p>\n<p class=\"abbildungsunterschrift\">Listing 1: Tabelle zur Protokollierung<\/p>\n<pre>CREATE TABLE dbo.OrdersLog\n(\nLdfNr int NOT NULL IDENTITY(1,1),\nController int NOT NULL,\nEmployeeId int NOT NULL,\nCustomerId varchar(5) NOT NULL,\nOrderId int NOT NULL,\nProductId int NOT NULL,\nUnitPrice money,\nQuantity smallint,\nDiscount real\n)<\/pre>\n<p>Im Trigger selbst m&uuml;ssen nur die betroffenen Datens&auml;tze, also jene mit Rabatten zwischen 10 und 20 Prozent, in die neue Tabelle geschrieben werden. Listing 2 zeigt die SQL-Anweisungen f&uuml;r diese Protokollierung.<\/p>\n<p class=\"abbildungsunterschrift\">Listing 2: Protokollierungs-Trigger<\/p>\n<pre>ALTER TRIGGER [dbo].[trg_Discount] ON [dbo].[Order Details]\nAFTER UPDATE, INSERT\nAS\nBEGIN\nSET NOCOUNT ON;\nIF UPDATE (Discount)\nBEGIN\nIF (select max(Discount) from inserted inner join\ndbo.orders on inserted.orderid =\ndbo.orders.orderid inner join employees on\ndbo.orders.employeeid = dbo.employees.employeeid\nwhere reportsto is not null) &gt; &apos;0.25&apos;\nBEGIN\nRAISERROR (N&apos;Es darf maximal ein Rabatt\nvon 0.25 gew&auml;hrt werden!&apos;,10,1);\nROLLBACK TRAN\nEND\nEND\nEND;<\/pre>\n<p>Die Protokollierung besteht aus einer einzigen <b>INSERT<\/b>-Anweisung. Soweit ist der Code des Triggers nichts wirklich Neues f&uuml;r Sie. Aber eine Besonderheit bietet dieser Code dennoch: Im Trigger wird die Funktion <b>Update() <\/b>verwendet.<\/p>\n<p>Mit dieser nur in Triggern verf&uuml;gbaren Funktion wird gepr&uuml;ft, ob der Wert der dort angegebenen Spalte ver&auml;ndert wurde &#8211; vorausgesetzt jedoch, die dort angegebene Spalte befindet sich auch in der manipulierten Tabelle.<\/p>\n<p>Die Existenz der angegebenen Spalte wird nur bei der Ausf&uuml;hrung des Triggers gepr&uuml;ft, jedoch nicht beim Anlegen oder &auml;ndern des Triggers. Sie sollten also die Schreibweise der Spalte vor dem Speichern des Triggers nochmals genau pr&uuml;fen.<\/p>\n<p>Einen neuen Trigger speichern Sie durch die Ausf&uuml;hrung des Skripts. F&uuml;r nachtr&auml;gliche &auml;nderungen am Trigger m&uuml;ssen Sie den <b>CREATE TRIGGER<\/b>-Befehl zu einem <b>ALTER TRIGGER <\/b>&auml;ndern, da nur mit diesem Befehl bestehende Trigger ver&auml;ndert werden k&ouml;nnen.<\/p>\n<p>Nach dem Speichern und der Neuanlage des Triggers <b>trg_OrdersLog<\/b> m&ouml;chten Sie diesen bestimmt testen. Den Trigger k&ouml;nnen Sie durch das Anlegen eines neuen Datensatzes oder durch das &auml;ndern eines bestehenden Datensatzes in der Tabelle <b>Order Details<\/b> ausl&ouml;sen. In beiden F&auml;llen muss zur Protokollierung allerdings ein Discount zwischen 0,10 und 0,25 eingegeben werden.<\/p>\n<p>Die erste SQL-Anweisung, die Sie zum Test eingeben k&ouml;nnen, legt einen neuen Datensatz in der Tabelle <b>Order Details <\/b>an:<\/p>\n<pre>INSERT INTO dbo.[Order Details]\nVALUES(11077, 77, &euro;&#353;6.5&euro;, 5, &euro;&#353;0.14&euro;)<\/pre>\n<p>Der <b>AFTER<\/b>-Trigger hat nach diesem Insert dann in der Tabelle <b>OrdersLog<\/b> die erste Protokollierung angelegt. Um es dem Anwender nicht zu einfach zu machen, die Protokollierung zu umgehen, werden auch nachtr&auml;gliche &auml;nderungen an einem Rabatt protokolliert, sofern dieser zwischen 10 und 25 Prozent liegt. <\/p>\n<p>Dies k&ouml;nnen Sie mit einer Update-Anweisung an dem neu hinzugef&uuml;gten Datensatz testen:<\/p>\n<pre>UPDATE dbo.[Order Details] SET Discount = &euro;&#353;0.14&euro; WHERE OrderId = 11077 AND ProductId = 77<\/pre>\n<p>Auch diese Datenmanipulation wurde in der Tabelle <b>OrdersLog<\/b> protokolliert. Die Eintr&auml;ge werden nach folgender <b>SELECT<\/b>-Anweisung ausgegeben:<\/p>\n<pre>SELECT * FROM dbo.OrdersLog<\/pre>\n<p>In Abb. 2 sehen Sie das Ergebnis dieser Pr&uuml;fung.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2008_06\/Trigger-web-images\/Bild23435_opt.jpeg\" alt=\"missing image file\" \/><\/p>\n<p class=\"abbildungsunterschrift\">Abb. 2: Die Protokollierung<\/p>\n<p>So weit, so gut. Was aber, wenn der Benutzer nun mehr als 25 Prozent Rabatt gew&auml;hrt? Einen solchen Rabatt m&ouml;chte der Abteilungsleiter erst gar nicht in seiner Auswertung sehen, sondern diese Eingabe soll von vornherein vermieden werden. Daf&uuml;r brauchen Sie keinen Trigger, denn diese Anforderung kann bereits mit einer Einschr&auml;nkung realisiert werden. <\/p>\n<p>Und wenn diese Regelung nur f&uuml;r Mitarbeiter gilt, nicht aber f&uuml;r den Chef selbst? F&uuml;r eine solche Anforderung reicht die Funktion einer Einschr&auml;nkung nicht aus, denn hierzu muss zun&auml;chst gepr&uuml;ft werden, ob der Benutzer einfacher Mitarbeiter oder der Chef des Hauses ist. Diese Anforderung kann entweder mit einem <b>AFTER<\/b>-Trigger oder mit einem <b>INSTEAD OF<\/b>-Trigger realisiert werden. <\/p>\n<p>Die Gesch&auml;ftsregel wird bei einem <b>AFTER<\/b>-Trigger erst nach der bereits durchgef&uuml;hrten Datenmanipulation gepr&uuml;ft. Insofern muss die Aktion bei Verletzen der Regel wieder r&uuml;ckg&auml;ngig gemacht werden.<\/p>\n<p>Wie auch beim Trigger <b>trg_OrdersLog<\/b> erfolgt die Pr&uuml;fung nur auf die Spalte <b>Discount<\/b> und auch nur dann, wenn sich der Wert der Spalte ver&auml;ndert hat. Der Status des Mitarbeiters wird anhand der Spalte <b>ReportsTo<\/b> in der Tabelle <b>Employees<\/b> ermittelt. Ist diese Spalte leer, gibt es f&uuml;r den entsprechenden Mitarbeiter niemanden, an den er Bericht erstatten muss. Ein Mitarbeiter in einer solchen Position ist meist auch der Chef des Hauses. <\/p>\n<p>Anhand dieser Definition wird nun der maximale Wert der Spalte <b>Discount<\/b> der <b>inserted<\/b>-Tabelle ermittelt. Enth&auml;lt die Spalte <b>Discount<\/b> nach der &auml;nderung einen Wert gr&ouml;&szlig;er 0,25, wird per <b>RAISERROR <\/b>eine Fehlermeldung ausgegeben (Abb. 3) und die Daten&auml;nderungen werden per ROLLBACK wieder auf den Zustand vor der Datenmanipulation gesetzt. <\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2008_06\/Trigger-web-images\/Bild23456_opt.jpeg\" alt=\"missing image file\" \/><\/p>\n<p class=\"abbildungsunterschrift\">Abb. 3: Trigger in Aktion<\/p>\n<p>Die Umsetzung der Anforderung mit einem <b>AFTER<\/b>-Trigger sehen Sie in Listing 3. <\/p>\n<p class=\"abbildungsunterschrift\">Listing 3: Pr&uuml;fung per AFTER-Trigger<\/p>\n<pre>ALTER TRIGGER [dbo].[trg_OrdersLog] ON [dbo].[Order Details]\nAFTER UPDATE, INSERT\nAS\nBEGIN\nSET NOCOUNT ON;\nIF UPDATE(Discount)\nBEGIN\nINSERT INTO dbo.OrdersLog\n(Controller, EmployeeId, CustomerId,\nOrderId, ProductId, UnitPrice,\nQuantity, Discount)\nSELECT IsNull(ReportsTo, 0),\ndbo.Orders.EmployeeId, dbo.Orders.CustomerId,\ninserted.OrderId, inserted.ProductId, inserted.UnitPrice,\ninserted.Quantity, inserted.Discount\nFROM inserted\nINNER JOIN dbo.Orders\nON inserted.OrderId = dbo.Orders.OrderId\nINNER JOIN dbo.Employees\nON dbo.Orders.EmployeeId = dbo.Employees.EmployeeId\nWHERE inserted.Discount &gt;= &apos;0.10&apos;\nAND inserted.Discount &lt;= &apos;0.25&apos;\nEND;\nEND;<\/pre>\n<p>Bei der Variante mit dem <b>INSTEAD OF<\/b>-Trigger wird kein <b>ROLLBACK <\/b>ben&ouml;tigt, da die Datenmanipulation erst gar nicht ausgef&uuml;hrt wird, wenn die Gesch&auml;ftsregel nicht eingehalten wurde. <\/p>\n<p>Listing 4 zeigt die Umsetzung der Anforderung mit einem <b>INSTEAD OF<\/b>-Trigger. <\/p>\n<p class=\"abbildungsunterschrift\">Listing 4: Pr&uuml;fung per INSTEAD OF-Trigger<\/p>\n<pre>ALTER TRIGGER [dbo].[trg_Discount] ON [dbo].[Order Details]\nINSTEAD OF UPDATE, INSERT\nAS\nBEGIN\nSET NOCOUNT ON;\nIF UPDATE (Discount)\nBEGIN\nIF (select max(Discount) from inserted inner join\ndbo.orders on inserted.orderid = dbo.orders.orderid\ninner join employees on dbo.orders.employeeid =\ndbo.employees.employeeid where reportsto is not\nnull) &gt; &apos;0.25&apos;\nBEGIN\nRAISERROR (N&apos;Es darf maximal ein Rabatt von 0.25\ngew&auml;hrt werden!&apos;,10,1);\nRETURN\nEND\nUPDATE OD SET Discount = i.Discount FROM\ndbo.[Order Details] OD join inserted i\nON OD.OrderId = i.OrderId AND OD.ProductId =\ni.ProductId join deleted d ON OD.OrderId =\ni.OrderId AND OD.ProductId = i.ProductId\nIF @@RowCount = 0\nBEGIN\nINSERT INTO dbo.[Order Details] SELECT *\nFROM inserted i\nEND\nEND\nEND;<\/pre>\n<p>Auch hier erfolgt die Pr&uuml;fung der Gesch&auml;ftsregel in Abh&auml;ngigkeit davon, ob sich der Wert der Spalte <b>Discount<\/b> durch die Datenmanipulation ver&auml;ndert hat. Der Mitarbeiterstatus wird wie beim <b>AFTER<\/b>-Trigger &uuml;ber die Spalte <b>ReportsTo<\/b> ermittelt. Bei einem Rabatt von mehr als 25 Prozent und der Identifizierung des Benutzers als Mitarbeiter wird der Benutzer zun&auml;chst durch eine Fehlermeldung (ausgel&ouml;st durch <b>RAISERROR<\/b>) auf die falsche Eingabe hingewiesen (Abb. 3) und danach der Trigger mittels RETURN beendet. <\/p>\n<p>Da ein <b>INSTEAD OF<\/b>-Trigger die eigentliche Datenmanipulation durch eigene Anweisungen ersetzt &#8211; was durch Ausl&ouml;sen der Fehlermeldung und Beenden durch <b>Return <\/b>auch erfolgreich umgesetzt wurde &#8211; werden keine Datenmanipulationen durchgef&uuml;hrt. Der Versuch, einen h&ouml;heren Rabatt als 25 Prozent zu erfassen, wurde auf diese Art verhindert.<\/p>\n<p>Das Ersetzen der eigentlichen Datenmanipulation durch eigene SQL-Anweisungen bedeutet aber auch, dass im positiven Fall der Pr&uuml;fung die eigentliche Datenmanipulation im Trigger nochmals ausgel&ouml;st werden muss. Aus diesem Grund muss die Update-Anweisung wie auch der Insert-Befehl f&uuml;r die beiden m&ouml;glichen Datenmanipulationen im Trigger enthalten sein. Die Werte f&uuml;r die einzelnen Aktionen k&ouml;nnen aus den Tabellen <b>inserted <\/b>und <b>deleted <\/b>gelesen werden.<\/p>\n<p>Durch den Trigger wird die Datenmanipulation verhindert, sobald die Gesch&auml;ftsregel verletzt wird. Es gibt an dieser Regel kein Vorbeikommen. Dies gilt f&uuml;r Datenmanipulationen an einzelnen Datens&auml;tzen wie auch f&uuml;r Datenmanipulationen mehrerer Datens&auml;tze, etwa bei Massenimporten oder Massen&auml;nderungen.<\/p>\n<p>Sobald in einem Massenimport oder bei einer Massen&auml;nderung in nur einer Bestellposition ein Rabatt von mehr als 25 Prozent gew&auml;hrt wird, wird der komplette Vorgang mit einem Fehler beendet. Bei einem <b>AFTER<\/b>-Trigger sorgt dann das <b>ROLLBACK <\/b>f&uuml;r das Zur&uuml;cksetzen der bereits geschriebenen Daten&auml;nderungen in den Zustand vor der &auml;nderung, w&auml;hrend bei einem <b>INSTEAD OF<\/b>-Trigger die eigentliche Datenmanipulation bereits vorher verhindert wird. Dadurch werden leider auch jene Datens&auml;tze des Massenimports beziehungsweise der Massen&auml;nderung nicht ver&auml;ndert, bei denen die Gesch&auml;ftsregel durchaus eingehalten wurde.<\/p>\n<p>Um in einem solchen Fall nach der Aschenputtel-Methode (&#8222;die Guten ins T&ouml;pfchen, die Schlechten ins Kr&ouml;pfchen&#8220;) zu verfahren, sprich: die Datens&auml;tze zu verarbeiten, die den Gesch&auml;ftsregeln entsprechen, und nur die Datenmanipulationen zu verhindern, die gegen die Regel versto&szlig;en, muss die Verarbeitung im Trigger erweitert werden, indem jeder einzelne Datensatz der <b>inserted<\/b>-Tabelle gepr&uuml;ft wird.<\/p>\n<p>Eine solche Pr&uuml;fung ist nur in einem <b>INSTEAD OF<\/b>-Trigger m&ouml;glich. Nur dort k&ouml;nnen die &#8222;guten&#8220; von den &#8222;schlechten&#8220; Datens&auml;tzen vorab &uuml;ber eine <b>IF<\/b>-Anweisung getrennt werden. Wobei die &#8222;Guten&#8220; ins T&ouml;pfchen, also in die Tabelle, geleitet und die &#8222;Schlechten&#8220; ins Kr&ouml;pfchen, etwa in eine Protokolldatei, gelegt werden k&ouml;nnten. Eine solche Einzelverarbeitung wirkt sich nat&uuml;rlich negativ auf die Performance der Datenverarbeitung aus.<\/p>\n<p>Mit einem <b>AFTER<\/b>-Trigger ist eine solche Trennung nicht realisierbar, da er die Gesch&auml;ftsregel erst nach der Datenmanipulation pr&uuml;ft. Ein dann ausgel&ouml;stes <b>ROLLBACK <\/b>gilt f&uuml;r alle Datens&auml;tze. Ein <b>ROLLBACK <\/b>f&uuml;r einzelne Datens&auml;tze ist nicht m&ouml;glich.<\/p>\n<p>Sie sehen, es gibt unterschiedliche Einsatzm&ouml;glichkeiten f&uuml;r die beiden Trigger-Typen. Welchen Trigger-Typ Sie f&uuml;r welches Szenario einsetzen, kommt auf die jeweilige Anforderung an. <\/p>\n<p>An dieser Stelle sei noch ein weiterer Trigger-Typ erw&auml;hnt, der im Zusammenhang mit dem SQL Server immer wieder genannt wird: Der <b>BEFORE<\/b>-Trigger. Dieser Beitrag enth&auml;lt aber weder eine Beschreibung, noch ein Skript zum Thema <b>BEFORE<\/b>-Trigger. Ganz einfach: Der SQL Server bietet keine <b>BEFORE<\/b>-Trigger. Mit <b>BEFORE<\/b>-Triggern beim MS SQL Server verh&auml;lt es sich wie mit dem Yeti im Himalaya. Es wird immer mal wieder behauptet, dass es ihn gibt, aber gesehen hat ihn noch keiner.<\/p>\n<p>Auf den ersten Blick scheinen Trigger durch die automatisierte Ausf&uuml;hrung die erste Wahl bei der Datenbankentwicklung zu sein. Immerhin k&ouml;nnen Sie hier die Regeln der Gesch&auml;ftslogik und der Datenkonsistenz fest an Tabellen und die jeweiligen Aktionen der Datenmanipulationen binden. Doch wie eingangs erw&auml;hnt, ist der Einsatz von Triggern immer wieder Bestandteil diverser Diskussionen &#8211; zu Recht.<\/p>\n<h2>Pro und Contra<\/h2>\n<p>Die eben erw&auml;hnte Einhaltung der technischen Gesch&auml;ftsregeln und die Sicherstellung der Datenkonsistenz sind auch ein Argument f&uuml;r Trigger. <\/p>\n<p>In manchen F&auml;llen k&ouml;nnen Trigger sogar die einzige Chance sein, diese Anforderungen in einer Datenbank umzusetzen. Besonders dann, wenn Sie keine M&ouml;glichkeit haben, in diese Datenbank gespeicherte Prozeduren aufzunehmen. Denn auch mit gespeicherten Prozeduren k&ouml;nnen Sie &#8211; wie im vorangegangenen Artikel dieser Serie beschrieben &#8211; die Datenkonsistenz gew&auml;hrleisten und die Gesch&auml;ftslogik abbilden. <\/p>\n<p>Stellen Sie sich das Gesicht eines Projektleiters vor, dem Sie zur Vermeidung von Dateninkonsistenzen die Kapselung jeder Gesch&auml;ftslogik in gespeicherten Prozeduren vorschlagen. Es m&uuml;ssten pro Tabelle verschiedene gespeicherte Prozeduren programmiert werden und auch das Frontend m&uuml;sste dementsprechend angepasst werden. Dieser recht gro&szlig;e Aufwand kann durch den Einsatz von Triggern minimiert werden.<\/p>\n<p>Doch nur in solchen Situationen sind Trigger den gespeicherten Prozeduren vorzuziehen. Sobald Sie die M&ouml;glichkeit haben, die Regeln zur Gesch&auml;ftslogik und Datenkonsistenz in gespeicherten Prozeduren abzubilden, sollten Sie diese M&ouml;glichkeit nutzen und auf Trigger verzichten. Der Einsatz von gespeicherten Prozeduren ist weitaus effektiver.<\/p>\n<p>Dies ist nicht nur in der flexibleren Art und in umfangreicheren M&ouml;glichkeiten zur Programmierung begr&uuml;ndet, sondern auch in der Chance, die Regeln und Algorithmen zur Verwaltung der Daten einer oder mehrerer Tabellen in einer gespeicherten Prozedur zu kapseln. Der Code zur Einhaltung der Datenkonsistenz und der Gesch&auml;ftslogik liegt in einem einzigen Objekt &#8211; der gespeicherten Prozedur &#8211; und ist somit leichter zu pflegen.<\/p>\n<p>Keine der anfangs erw&auml;hnten Einsatzm&ouml;glichkeiten eines Triggers kann nicht auch mit einer gespeicherten Prozedur realisiert werden: Die Bildung von Summen als redundante Datenhaltung l&auml;sst sich beim &auml;ndern der Positionss&auml;tze ermitteln und innerhalb einer Transaktion direkt im Rechnungskopf ver&auml;ndern, Standardwerte k&ouml;nnen aus anderen Tabellen abgeleitet und als Konstanten in der SQL-Anweisung &uuml;bergeben werden, Protokollierungen von Datenmanipulationen k&ouml;nnen mit einer Transaktion umgesetzt werden, die die SQL-Anweisung der jeweiligen Datenmanipulation wie auch die SQL-Anweisung zur Protokollierung in einer anderen Tabelle enth&auml;lt, und Dateneingaben k&ouml;nnen vor der Datenmanipulation gepr&uuml;ft und gegebenenfalls vermieden werden. <\/p>\n<p>Sogar die Daten der Tabellen <b>inserted <\/b>und <b>deleted <\/b>k&ouml;nnen Sie ab dem SQL Server 2005 in einer gespeicherten Prozedur verwenden. Schauen Sie sich in der Hilfe (BOL) einfach mal den Befehl <b>OUTPUT <\/b>an.<\/p>\n<p>In den gespeicherten Prozeduren haben Sie nicht nur mehr M&ouml;glichkeiten zur Programmierung, auch die Pflege gestaltet sich leichter. Durch den Umstand, dass Trigger immer fest mit einer Tabelle verbunden sind, m&uuml;ssen Sie wissen, an welcher Tabelle welche Trigger definiert sind.<\/p>\n<p>Das SQL Server Management Studio bietet Ihnen keine tabellen&uuml;bergreifende &Uuml;bersicht aller Trigger. Dies sieht bei den gespeicherten Prozeduren anders aus. In der Datenbank gibt es unter dem Knoten <b>Programmierbarkeit <\/b>einen eigenen Zweig namens <b>Gespeicherte Prozeduren<\/b>. Dort sind alle gespeicherten Prozeduren Ihrer Datenbank zu finden.<\/p>\n<p>Auch die Fehlersuche gestaltet sich mit gespeicherten Prozeduren einfacher. Durch den Quellcode im Frontend wie auch im SQL Server sind die Aufrufe der gespeicherten Prozeduren direkt zu erkennen. Ein Trigger jedoch ist im Quellcode nicht zu finden, da er ja nicht manuell ausgef&uuml;hrt wird. Trigger sind nicht transparent und werden bei einer Fehlersuche meist erst als letzte Ursache in Betracht gezogen. Dies kann die Suche nach einem Fehler stark in die L&auml;nge ziehen. <\/p>\n<p>Neben den bisher eher konzeptionellen Gr&uuml;nden gibt es auch im Bereich Performance einige Punkte, die gegen den Einsatz von Triggern sprechen. Microsoft weist in den BOL explizit darauf hin, dass ein inflation&auml;rer Gebrauch von Triggern das Datenbanksystem durchaus verlangsamen kann. Trigger eskalieren leicht zur Performance-Bremse. <\/p>\n<p>Die Empfehlung in den BOL geht so weit, &#8222;die in den Tabellendefinitionen vorhandenen M&ouml;glichkeiten, wie referentielle Integrit&auml;t, Standardwerte und Einschr&auml;nkungen, f&uuml;r die Einhaltung der Datenkonsistenz und Gesch&auml;ftsregeln zu nutzen, bevor man den Einsatz eines Triggers in Betracht zieht. Ein Trigger sollte erst dann genutzt werden, wenn die in den Tabellendefinitionen vorhandenen M&ouml;glichkeiten f&uuml;r Ihre Anforderungen nicht mehr ausreichen&#8220;. <\/p>\n<p>Der Grund f&uuml;r die schlechte Performance liegt in der Architektur von Triggern. Trigger werden bei jeder Datenmanipulation ausgel&ouml;st. Sofern sich die SQL-Anweisungen im Trigger nicht direkt auf die tempor&auml;ren Tabellen <b>inserted <\/b>und <b>deleted <\/b>beziehen, werden diese Anweisungen nur einmal pro Aktion ausgef&uuml;hrt. Anweisungen, die sich auf die Tabellen <b>inserted <\/b>und <b>deleted <\/b>beziehen, werden pro ge&auml;ndertem Datensatz ausgef&uuml;hrt. Dies wirkt sich gerade bei Massenimporten negativ auf die Performance aus.<\/p>\n<p>Stellen Sie sich einen t&auml;glichen Import von mehreren tausend Bestellungen mit durchschnittlich 20 bis 50 Bestellpositionen in die Datenbank <b>Northwind <\/b>vor. Pro Bestellposition w&uuml;rden die beiden Beispiel-Trigger <b>trg_OrdersLog<\/b> und <b>trg_Discount<\/b> ausgel&ouml;st.<\/p>\n<p>Die darin enthaltenen Pr&uuml;fungen werden unerbittlich ausgef&uuml;hrt, was Zeit kostet und den Massenimport verlangsamt. Nat&uuml;rlich k&ouml;nnten Sie f&uuml;r einen solchen Import die Trigger deaktivieren, aber dann h&auml;tten Sie eventuell auch Bestellpositionen mit einem Rabatt gr&ouml;&szlig;er 25 Prozent oder Rabatten zwischen 10 und 25 Prozent, ohne dass diese protokolliert wurden.<\/p>\n<p>Die definierte Gesch&auml;ftsregel rund um den Rabatt w&uuml;rde an dieser Stelle nicht greifen. Der Import mitsamt der Pr&uuml;fung dieser Gesch&auml;ftsregel w&auml;re mit einer gespeicherten Prozedur eleganter und bei weitem schneller. <\/p>\n<p>Aber auch au&szlig;erhalb des SQL Servers kann es einige Gr&uuml;nde gegen Trigger geben. Gerade bei Access sorgen Trigger immer wieder f&uuml;r &Uuml;berraschungen. <\/p>\n<h2>Trigger und Access<\/h2>\n<p>Auch wenn es bereits indirekt erw&auml;hnt wurde, sollen hier der Vollst&auml;ndigkeit halber noch Verwendungsm&ouml;glichkeiten von Triggern unter Access aufgez&auml;hlt werden. Es ist schlicht so: Es gibt keine. <\/p>\n<p>Ein Trigger wird ja automatisch bei einer Datenmanipulation an einer Tabelle aufgerufen. Ein manueller Aufruf eines Triggers ist weder im SQL Server noch in Access m&ouml;glich.<\/p>\n<p>Aber gerade diese automatische Ausf&uuml;hrung eines Triggers sorgt bei Access immer wieder gerne f&uuml;r Verwirrung. Dies betrifft insbesondere <b>AFTER<\/b>-Trigger, die nach der eigentlichen Datenmanipulation den ge&auml;nderten Datensatz nochmals &auml;ndern.<\/p>\n<p>In Listing 5 sehen Sie den Trigger <b>trg_LastModified<\/b>, der nach einer <b>UPDATE<\/b>-Anweisung an der Tabelle <b>Employees<\/b> die Spalte <b>LastModified<\/b> des ge&auml;nderten Datensatzes mit dem aktuellen Datum aktualisiert, um den Zeitpunkt der letzten &auml;nderung festzuhalten.<\/p>\n<p class=\"abbildungsunterschrift\">Listing 5: Letztes &auml;nderungsdatum einstellen<\/p>\n<pre>CREATE TRIGGER [dbo].[trg_LastModified] ON [dbo].[Employees]\nAFTER UPDATE, INSERT\nAS\nBEGIN\nSET NOCOUNT ON;\nIF NOT UPDATE(LastModified)\nBEGIN\nUPDATE dbo.Employees\nSET LastModified = getdate()\nWHERE EmployeeId IN (SELECT EmployeeId FROM inserted)\nEND;\nEND;<\/pre>\n<p>Dieser Trigger wird bei jeder &auml;nderung des Datensatzes ausgef&uuml;hrt, sofern der Wert der Spalte <b>LastModified<\/b> nicht ge&auml;ndert wurde. <\/p>\n<p>Der Trigger wird auch dann ausgel&ouml;st, wenn Sie den Datensatz in Access &auml;ndern. Wenn Sie den Datensatz ein zweites Mal &auml;ndern m&ouml;chten, m&uuml;ssen Sie die Datenanzeige in Access zun&auml;chst aktualisieren. Ohne diese Aktualisierung erhalten Sie die Fehlermeldung, dass der Datensatz bereits von einem anderen Benutzer ge&auml;ndert wurde (s. Abb. 4). Dieser andere Benutzer war der Trigger!<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2008_06\/Trigger-web-images\/Bild23463_opt.jpeg\" alt=\"missing image file\" \/><\/p>\n<p class=\"abbildungsunterschrift\">Abb. 4: Der Benutzer &#8222;Trigger&#8220;<\/p>\n<p>Trigger haben noch eine weitere Eigenheit, die f&uuml;r Verwirrung sorgen kann. Die einzelnen SQL-Anweisungen innerhalb eines Triggers l&ouml;sen immer die bereits erw&auml;hnten <b>DONE_IN_PROC<\/b>-Meldungen aus, die an den Client die Information <b>xx rows affected<\/b> &uuml;bertragen.<\/p>\n<p>Access kann je nach Access-Version und eingesetztem Treiber auf diese Gespr&auml;chigkeit mit der Fehlermeldung &#8222;Die Schl&uuml;sselspalteninformationen sind ungen&uuml;gend oder inkorrekt. Es sind zu viele Zeilen von der Aktualisierung betroffen&#8220; reagieren. Insofern sollten Sie die <b>DONE_IN_PROC<\/b>-Meldungen im Trigger durch die SQL-Anweisung <b>SET NOCOUNT ON <\/b>unbedingt unterbinden.<\/p>\n<h2>Fazit<\/h2>\n<p>Sie sehen, es gibt einige Gr&uuml;nde gegen und einige f&uuml;r Trigger. Letztendlich ist die Entscheidung nicht von der Gesinnung des &#8222;Glaubenskriegers&#8220; abh&auml;ngig, sondern von den Anforderungen des Kunden, die technisch m&ouml;glichst effizient umgesetzt werden sollen. <\/p>\n<p>Sofern Sie keine gespeicherten Prozeduren einsetzen k&ouml;nnen oder d&uuml;rfen, sind Trigger die einzige Chance, die Daten Ihrer Datenbank mit datenbankeigenen Mitteln konsistent zu halten. Bietet sich Ihnen aber die M&ouml;glichkeit, die Gesch&auml;ftsregeln in gespeicherten Prozeduren zu kapseln, sollten Sie diese Methode den Triggern vorziehen. Sie sollten aber auf alle F&auml;lle versuchen, ein Gemisch aus Triggern und gespeicherten Prozeduren zu vermeiden, denn damit machen Sie sich &uuml;ber kurz oder lang nur das Leben schwer.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>Skript 1.sql<\/p>\n<p>Skript 2.sql<\/p>\n<p>Skript 3.sql<\/p>\n<p>Skript 4.sql<\/p>\n<p>Skript 5.sql<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/13600952-7C3A-4353-A4F9-36B8183C1F51\/aiu_636.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8222;Trigger oder nicht Trigger. Das ist hier die Frage.&#8220;, w&auml;re wohl die Aussage von Hamlet gewesen, h&auml;tte er sich mit Datenbankentwicklung und nicht mit anderen Trag&ouml;dien besch&auml;ftigt. Eine Entscheidung f&uuml;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&uuml;r oder gegen Trigger werden, sondern die grunds&auml;tzliche Funktionsweise von Triggern erkl&auml;ren und Ihnen einige Informationen liefern, auf deren Grundlage Sie Ihre eigene Meinung bilden k&ouml;nnen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662008,66062008,44000022,44000021],"tags":[],"class_list":["post-55000636","post","type-post","status-publish","format-standard","hentry","category-662008","category-66062008","category-SQL_Server_und_Co","category-Tabellen_und_Datenmodellierung"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Trigger - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/trigger\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Trigger\" \/>\n<meta property=\"og:description\" content=\"&quot;Trigger oder nicht Trigger. Das ist hier die Frage.&quot;, w&auml;re wohl die Aussage von Hamlet gewesen, h&auml;tte er sich mit Datenbankentwicklung und nicht mit anderen Trag&ouml;dien besch&auml;ftigt. Eine Entscheidung f&uuml;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&uuml;r oder gegen Trigger werden, sondern die grunds&auml;tzliche Funktionsweise von Triggern erkl&auml;ren und Ihnen einige Informationen liefern, auf deren Grundlage Sie Ihre eigene Meinung bilden k&ouml;nnen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/trigger\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2023-03-12T18:09:26+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-02-19T08:24:08+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg03.met.vgwort.de\/na\/3f273a18602a4f13a135811626535088\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"27\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Trigger\",\"datePublished\":\"2023-03-12T18:09:26+00:00\",\"dateModified\":\"2024-02-19T08:24:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/\"},\"wordCount\":5254,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg03.met.vgwort.de\\\/na\\\/3f273a18602a4f13a135811626535088\",\"articleSection\":[\"2008\",\"6\\\/2008\",\"SQL Server und Co.\",\"Tabellen und Datenmodellierung\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/\",\"name\":\"Trigger - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg03.met.vgwort.de\\\/na\\\/3f273a18602a4f13a135811626535088\",\"datePublished\":\"2023-03-12T18:09:26+00:00\",\"dateModified\":\"2024-02-19T08:24:08+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg03.met.vgwort.de\\\/na\\\/3f273a18602a4f13a135811626535088\",\"contentUrl\":\"http:\\\/\\\/vg03.met.vgwort.de\\\/na\\\/3f273a18602a4f13a135811626535088\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/trigger\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Trigger\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Trigger - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/trigger\/","og_locale":"de_DE","og_type":"article","og_title":"Trigger","og_description":"\"Trigger oder nicht Trigger. Das ist hier die Frage.\", w&auml;re wohl die Aussage von Hamlet gewesen, h&auml;tte er sich mit Datenbankentwicklung und nicht mit anderen Trag&ouml;dien besch&auml;ftigt. Eine Entscheidung f&uuml;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&uuml;r oder gegen Trigger werden, sondern die grunds&auml;tzliche Funktionsweise von Triggern erkl&auml;ren und Ihnen einige Informationen liefern, auf deren Grundlage Sie Ihre eigene Meinung bilden k&ouml;nnen.","og_url":"https:\/\/access-im-unternehmen.de\/trigger\/","og_site_name":"Access im Unternehmen","article_published_time":"2023-03-12T18:09:26+00:00","article_modified_time":"2024-02-19T08:24:08+00:00","og_image":[{"url":"http:\/\/vg03.met.vgwort.de\/na\/3f273a18602a4f13a135811626535088","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"27\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/trigger\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/trigger\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Trigger","datePublished":"2023-03-12T18:09:26+00:00","dateModified":"2024-02-19T08:24:08+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/trigger\/"},"wordCount":5254,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/trigger\/#primaryimage"},"thumbnailUrl":"http:\/\/vg03.met.vgwort.de\/na\/3f273a18602a4f13a135811626535088","articleSection":["2008","6\/2008","SQL Server und Co.","Tabellen und Datenmodellierung"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/trigger\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/trigger\/","url":"https:\/\/access-im-unternehmen.de\/trigger\/","name":"Trigger - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/trigger\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/trigger\/#primaryimage"},"thumbnailUrl":"http:\/\/vg03.met.vgwort.de\/na\/3f273a18602a4f13a135811626535088","datePublished":"2023-03-12T18:09:26+00:00","dateModified":"2024-02-19T08:24:08+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/trigger\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/trigger\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/trigger\/#primaryimage","url":"http:\/\/vg03.met.vgwort.de\/na\/3f273a18602a4f13a135811626535088","contentUrl":"http:\/\/vg03.met.vgwort.de\/na\/3f273a18602a4f13a135811626535088"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/trigger\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Trigger"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000636","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55000636"}],"version-history":[{"count":1,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000636\/revisions"}],"predecessor-version":[{"id":88075300,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000636\/revisions\/88075300"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55000636"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55000636"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55000636"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}