In SQL Server sind Trigger Datenbankobjekte, die immer dann ausgeführt werden, wenn ein auslösendes Ereignis in der Datenbank oder auf dem Server eintritt.
Auslöser spielen eine Schlüsselrolle bei der Erfüllung von Geschäftsanforderungen wie der Benachrichtigung bestimmter Personen, dem Start eines Jobs oder anderen Vorgängen. Da Trigger viele solcher Vorgänge verarbeiten können, sollten wir sie sorgfältig definieren, um Leistungseinbußen zu vermeiden.
In diesem Artikel werden wir Trigger, Triggertypen und verschiedene verfügbare Triggeroptionen untersuchen. Außerdem untersuchen wir die notwendigen Vorsichtsmaßnahmen bei der Verwendung von DML-Triggern.
Auslöser in SQL
Ein Trigger ist eine spezielle Art von gespeicherter Prozedur, die bei definierten Ereignissen ausgeführt wird und das im Trigger-Hauptteil definierte Skript ausführt. Es gibt mehrere Arten von Triggern:
- DML-Trigger – zum Ausführen von DML-Operationen wie INSERT-, UPDATE- und DELETE-Befehlen für Tabellen.
- DDL-Trigger – zum Ausführen von DDL-Operationen wie CREATE-, ALTER- und DROP-Befehlen über beliebige Objekte in der Datenbank oder auf dem Server.
- Anmeldeauslöser – für den Versuch, sich während des LOGON-Ereignisses bei einer Instanz von SQL Server anzumelden.
DML-Trigger in SQL Server
DML-Trigger werden von DML-Befehlen (INSERT, UPDATE oder DELETE) für Tabellen oder Ansichten ausgelöst. Wir können solche Trigger nur für die Tabellen oder Ansichten erstellen, in denen sich Daten befinden, damit sie DML-Befehle für sie akzeptieren.
Basierend auf dem Zeitpunkt des Auslösens/Aufrufs können DML-Trigger von den folgenden Typen sein:
- FÜR oder NACH Triggertyp – Der Trigger wird nach dem erfolgreichen Abschluss der DML-Anweisung für eine Tabelle oder Ansicht aufgerufen. Hinweis:Es ist möglich, den AFTER-Trigger nur für Tabellen zu erstellen, nicht für Ansichten.
- Statt Triggertyp – Der Trigger wird vor (anstatt) dem DML-Skript aufgerufen, das für die Tabelle oder Ansicht ausgeführt wird.
SQL Server erstellt zwei spezielle oder logische Tabellen namens INSERTED und AKTUALISIERT wenn DML-Trigger über Tabellen oder Ansichten hinweg erstellt werden. Diese logischen Tabellen helfen dabei, die Datensatzänderungen zu identifizieren, die über INSERT/UPDATE/DELETE-Operationen erfolgen. Auf diese Weise wird sichergestellt, dass DML-Trigger effektiv funktionieren.
- EINFÜGEN Die logische Tabelle speichert Kopien neuer Datensätze von Datensätzen, die während der INSERT- und UPDATE-Operationen geändert wurden. Wenn der aktuellen Tabelle ein neuer Datensatz hinzugefügt wird, wird er auch der INSERTED-Tabelle hinzugefügt. Ebenso verschieben alle Änderungen an bestehenden Datensätzen über die UPDATE-Anweisung die neuesten Werte in die INSERTED-Tabelle und ältere Werte in die logische DELETED-Tabelle.
- GELÖSCHT Die logische Tabelle speichert Kopien älterer Werte während der UPDATE- und DELETE-Operationen. Immer wenn ein Datensatz aktualisiert wird, werden ältere Werte in die DELETED-Tabelle kopiert. Immer wenn ein Datensatz aus der aktuellen Tabelle gelöscht wird, werden Datensätze in die DELETED-Tabelle eingefügt.
SQL Server verfügt über integrierte Funktionen COLUMN_UPDATED() und UPDATE() um das Vorhandensein von INSERT- oder UPDATE-Operationen in der jeweiligen Spalte zu identifizieren.
- COLUMN_UPDATED() gibt varbinary-Werte von Spalten zurück, die von den INSERT- oder UPDATE-Operationen betroffen waren.
- UPDATE() akzeptiert den Spaltennamen als Eingabeparameter und gibt die Information zurück, ob diese Spalte Datenänderungen als Teil der INSERT- oder UPDATE-Operationen aufweist.
Die NICHT ZUR REPLIKATION -Eigenschaft kann in DML-Triggern verwendet werden, um zu vermeiden, dass sie für Änderungen ausgelöst werden, die über den Replikationsprozess kommen.
DML-Trigger können auch mit .Net Framework Common Language Runtime (CLR) erstellt werden.
Das System-DMV sys.triggers speichert die Liste aller datenbankbezogenen Trigger. Wir können die folgende Abfrage verwenden, um die Details aller DML-Trigger in einer Datenbank abzurufen:
SELECT *
FROM sys.triggers
WHERE type = 'TR';
Die DML-Triggerdefinitionen können angezeigt werden, wenn der Trigger nicht verschlüsselt ist. Wir verwenden eine der folgenden Optionen:
sys.sql_modules
SELECT OBJECT_SCHEMA_NAME(object_id, db_id()) Schema_name, OBJECT_NAME(object_id) Trigger_Name, definition
FROM sys.sql_modules
WHERE object_id = OBJECT_ID(<trigger_name>);
OBJECT_DEFINITION() Funktion
SELECT OBJECT_DEFINITION (OBJECT_ID(<trigger_name>)) AS ObjectDefinition;
sp_helptext gespeicherte Prozedur
EXEC sp_helptext '<trigger_name>';
Alle möglichen DML-Ereignisse sind in sys.events verfügbar Tisch. Wir können sie mit der folgenden Abfrage anzeigen:
SELECT *
FROM sys.events;
Syntax des DML-Triggers
CREATE TRIGGER <trigger_name>
ON <schema_name.table_name | schema_name.view_name >
[ WITH <DML_trigger_option> [ ,...n ] ]
{ FOR | AFTER | INSTEAD OF} <event_type>
AS { sql_statement | EXTERNAL NAME <method specifier> }
Zu Demonstrationszwecken habe ich zwei Tabellen namens Sales erstellt und SalesHistory mit wenigen Spalten in der Testdatenbank:
CREATE TABLE Sales (SalesId int IDENTITY NOT NULL, SalesDate datetime, Itemcount int, price money);
CREATE TABLE SalesHistory (SalesId int NOT NULL, SalesDate datetime, Itemcount int, price money, ChangeType varchar(10), ChangeDate datetime DEFAULT GETDATE(), ChangedUser varchar(100) DEFAULT SUSER_NAME());
GO
Wie Sie sehen können, ist die SalesHistory Die Tabelle hat 3 zusätzliche Spalten, um das Änderungsdatum und den Benutzernamen zu verfolgen, der die Änderung ausgelöst hat. Bei Bedarf können wir eine weitere Identitätsspalte haben definieren und ihn auch zu einem Primärschlüssel machen.
INSERT-Trigger
Wir erstellen einen einfachen INSERT-Trigger für Sales Tabellen, um alle neuen Datensatzänderungen in SalesHistory einzufügen Tisch. Verwenden Sie das folgende Skript:
CREATE TRIGGER TR_INS_Sales ON Sales
FOR INSERT
AS
BEGIN
INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
SELECT SalesId
,SalesDate
,Itemcount
,price
,'INSERT'
FROM inserted
END
GO
Um die Triggersyntax zu erklären, haben wir einen DML-Trigger mit dem Namen TR_INS_Sales erstellt auf die Verkäufe Tisch. Es muss den Trigger nur für die INSERT-Operationen auslösen – das Einfügen von Datensätzen in die SalesHistory Tabelle aus der eingefügten Tabelle.
Wie wir wissen, eingefügt ist eine logische Tabelle, die die Änderungen erfasst, die in der Quelltabelle (der Sales Tabelle in unserem Fall).
Wir können sehen, dass eine weitere spezielle logische Tabelle im UPDATE-Trigger gelöscht wurde, weil deleted Tabelle gilt nicht für INSERT-Trigger.
Lassen Sie uns einen neuen Datensatz hinzufügen, um zu prüfen, ob Datensätze in SalesHistory eingefügt wurden Tabelle automatisch.
INSERT INTO Sales(SalesDate,Itemcount,price)
VALUES ('2021-01-01', 5, 100);
Obwohl wir nur einen Datensatz in Verkäufe eingefügt haben Tabelle erhalten wir 2 Zeilen der 1 betroffenen Zeile Botschaft. Der zweite Datensatz erscheint aufgrund der INSERT-Operation als Teil des Triggers, der von der INSERT-Aktivität auf Sales aufgerufen wird Tabelle – Einfügen eines Datensatzes in die SalesHistory Tabelle.
Lassen Sie uns die Aufzeichnungen über beide Verkäufe überprüfen und SalesHistory Tabellen:
SELECT *
FROM Sales
SELECT *
FROM SalesHistory
Wir können dieses ChangeDate sehen und ChangedUser werden automatisch ausgefüllt. Das liegt daran, dass wir unsere Geschichte entworfen haben Tabelle mit den Standardwerten als GETDATE() und SUSER_NAME() .
Endbenutzer können über Trigger oder andere Mittel sehen, dass ihr INSERT über die zusätzliche 1 betroffene Zeile geprüft wurde Botschaft. Wenn Sie Änderungen überwachen möchten, ohne die Benutzer zu informieren, müssen Sie SET ROWCOUNT ON anwenden Befehl. Es unterdrückt die Ergebnisse, die für DML-Operationen angezeigt werden, die innerhalb des Triggers stattfinden.
Lassen Sie uns unseren Trigger mithilfe des Skripts mit SET ROWCOUNT ON ÄNDERN Option und sehen Sie es in Aktion:
ALTER TRIGGER TR_INS_Sales ON Sales
FOR INSERT
AS
BEGIN
SET NOCOUNT ON
INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
SELECT SalesId
,SalesDate
,Itemcount
,price
,'INSERT'
FROM inserted
END
GO
Jetzt fügen wir einen weiteren Datensatz in Sales ein Tabelle:
INSERT INTO Sales(SalesDate,Itemcount,price)
VALUES ('2021-02-01', 1, 50);
Wir können nur eine einzige 1 betroffene Zeile sehen Botschaft. Daher wird die Zielgruppe möglicherweise überhaupt nicht benachrichtigt, dass ihre Aktionen überwacht werden.
Lassen Sie uns überprüfen, ob der INSERT-Trigger aufgerufen wurde, indem wir die Sales überprüfen und SalesHistory Tabellen.
Ja, das INSERT-Event auf den Verkäufen Tabelle wurde erfolgreich ausgelöst. Die Datensätze wurden in die SalesHistory eingefügt Tabelle, ohne Benutzer zu benachrichtigen.
Wenn Sie also Auslöser für Auditzwecke erstellen, wird SET NOCOUNT ON ist notwendig. Es ermöglicht Audits, ohne jemanden zu benachrichtigen.
UPDATE-Trigger
Vor dem Erstellen eines tatsächlichen UPDATE-Triggers auf Sales beziehen wir uns wieder auf die speziellen logisch eingefügten und gelöschten Tabellen. Erstellen Sie einen UPDATE-Beispieltrigger für Sales Tabelle:
CREATE TRIGGER TR_UPD_Sales ON Sales
FOR UPDATE
AS
BEGIN
SELECT * FROM inserted
SELECT * FROM deleted
END
GO
Der UPDATE-Trigger wurde erfolgreich erstellt. Lassen Sie uns nun einen neuen Datensatz falsch einfügen. Später werden wir es aktualisieren, um den UPDATE-Trigger in Aktion zu überprüfen:
INSERT INTO Sales(SalesDate,Itemcount,price)
VALUES ('2021-02-01', 1, 50);
Wir haben die folgenden Aufzeichnungen über die Verkäufe und SalesHistory Tabelle:
Lassen Sie uns SalesId =3 aktualisieren im Verkauf Tabelle mit neuen Werten. Wir sehen die Daten in den eingefügten und gelöschten Tabellen:
UPDATE Sales
SET SalesDate = '2021-03-01'
, Itemcount = 3
, price = 500
WHERE SalesId = 3
Wenn die UPDATE-Operation stattfindet, sind alle neuen oder geänderten Werte in der eingefügten Tabelle verfügbar, und alte Werte sind in der gelöschten Tabelle verfügbar:
Lassen Sie uns nun den UPDATE-Trigger mit dem folgenden Skript ändern und in Aktion überprüfen:
ALTER TRIGGER TR_UPD_Sales ON Sales
FOR UPDATE
AS
BEGIN
INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
SELECT SalesId
,SalesDate
,Itemcount
,price
,'UPDATE'
FROM inserted
END
GO
Der UPDATE-Trigger wurde erfolgreich geändert, und wir können dasselbe UPDATE-Skript erneut ausführen:
Jetzt können wir die 1 betroffene Zeile sehen Nachricht zweimal. Es zeigt die Ausführung der UPDATE-Operation für Sales an Tabelle und die INSERT-Operation für die SalesHistory Tisch. Lassen Sie uns dies überprüfen, indem wir beide Tabellen auswählen:
Die UPDATE-Aktivität wurde in der SalesHistory verfolgt Tabelle als neuer Rekord. Vor diesem Datensatz haben wir einen weiteren, der anzeigt, wann der Datensatz zuerst eingefügt wurde.
Auslöser LÖSCHEN
Bisher haben wir das FOR getestet oder NACH Typ von Triggern für INSERT- oder UPDATE-Operationen. Jetzt können wir versuchen, statt zu verwenden Art des DML-Triggers für die DELETE-Operation. Verwenden Sie das folgende Skript:
CREATE TRIGGER TR_DEL_Sales ON Sales
INSTEAD OF DELETE
AS
BEGIN
RAISERROR ('Notify Sales Team', 16, 10);
END
GO
Der DELETE-Trigger wurde erfolgreich erstellt. Es sendet eine Fehlermeldung an den Client, anstatt den DELETE-Befehl für Sales auszuführen Tabelle.
Versuchen wir, den Datensatz SalesID =3 zu löschen aus dem Verkauf Tabelle mit dem folgenden Skript:
DELETE FROM Sales
WHERE SalesId = 3
Wir haben Benutzer daran gehindert, Datensätze aus Sales zu löschen Tisch. Der Trigger hat eine Fehlermeldung ausgegeben.
Überprüfen wir auch, ob der Datensatz aus Sales gelöscht wurde Tabelle und ob es Änderungen in der SalesHistory gab Tabelle:
Da wir das Trigger-Skript vor der eigentlichen DELETE-Anweisung mit INSTEAD OF-Trigger ausgeführt haben, war die DELETE-Operation auf SalesId=3 überhaupt nicht erfolgreich. Daher wurden keine Änderungen in beiden Verkäufen widergespiegelt und SalesHistory Tabelle.
Ändern wir den Trigger mit dem folgenden Skript, um den DELETE-Versuch in der Tabelle zu identifizieren:
ALTER TRIGGER TR_DEL_Sales ON Sales
INSTEAD OF DELETE
AS
BEGIN
INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
SELECT SalesId
,SalesDate
,Itemcount
,price
,'DELETE ATP'
FROM deleted
END
GO
Der Trigger wurde erfolgreich geändert. Lassen Sie uns die SalesId =3 löschen Datensatz aus den Verkäufen Tabelle erneut:
Die Ausführung der DELETE-Anweisung zeigt die 1 betroffene Zeile Nachricht zweimal. Sehen wir uns die Aufzeichnungen über die Verkäufe an und SalesHistory Tabellen, um zu sehen, was dort genau passiert:
Die im DELETE-Trigger verwendete Logik bestand darin, alle DELETE-Versuche in der Tabelle zu erfassen, ohne den Datensatz tatsächlich aus Sales zu löschen Tabelle mit dem INSTEAD OF Abzug. Wir können bestätigen, dass der Datensatz nicht aus den Verkäufen gelöscht wurde Tabelle und ein neuer Datensatz wurde in SalesHistory eingefügt Tabelle.
Ein einziger Trigger zur Verarbeitung von INSERT-, UPDATE- und DELETE-Operationen
Bis jetzt haben wir 3 Trigger erstellt, um die INSERT-, UPDATE- und DELETE-Operationen für eine einzelne Tabelle zu verarbeiten. Wenn wir mehrere Auslöser haben, wäre es schwierig, sie zu verwalten, insbesondere wenn sie nicht ordnungsgemäß dokumentiert sind. Es kann zu Leistungsproblemen kommen, wenn die Entwickler widersprüchliche Logik für mehrere Auslöser verwendet haben.
Ich persönlich empfehle die Verwendung eines einzelnen Triggers mit der gesamten Logik kombiniert, um potenzielle Datenverluste oder Leistungsprobleme zu vermeiden. Wir können versuchen, 3 Trigger in einem einzigen Trigger zu kombinieren, um eine bessere Leistung zu erzielen. Aber bevor wir das tun, sehen wir uns an, wie man bestehende Trigger DROPT und wie man Trigger deaktiviert oder aktiviert.
Drücker loslassen
Um 3 Trigger zu einem einzigen zusammenzuführen, müssen wir diese 3 Trigger zuerst DROPEN. Dies ist sowohl über SSMS- als auch über T-SQL-Ansätze möglich.
Erweitern Sie in SSMS den Test Datenbank > Tabellen > Verkäufe Tabelle> Auslöser .
Wir können unsere 3 bisher erstellten Trigger sehen:
Um einen Auslöser zu löschen, klicken Sie einfach mit der rechten Maustaste darauf> Löschen > OK .
Wenn Sie lieber T-SQL verwenden, sehen Sie sich die folgende Syntax an, um den Trigger zu löschen:
DROP TRIGGER <trigger_name>
Da ist der TR_INS_Sales Trigger, den wir für Sales erstellt haben Tisch. Das Skript lautet:
DROP TRIGGER TR_INS_Sales
Wichtig :Beim Löschen einer Tabelle werden standardmäßig alle Trigger gelöscht.
Auslöser deaktivieren und aktivieren
Anstatt den Auslöser fallen zu lassen, können wir ihn mit Deaktivieren vorübergehend deaktivieren Auslöser Option über SSMS oder T-SQL.
Klicken Sie in SSMS mit der rechten Maustaste auf den Trigger-Namen> Deaktivieren . Nach der Deaktivierung wird der Trigger nicht ausgelöst, bis Sie ihn wieder aktivieren.
Während der Trigger funktioniert, wird Enable Option ist ausgegraut. Wenn Sie es deaktivieren, wird das Aktivieren Option wird sichtbar und aktiv.
Wenn Sie lieber T-SQL verwenden, können Sie Trigger mithilfe der folgenden Skripts deaktivieren und aktivieren:
-- To Disable all triggers on a specific table
DISABLE TRIGGER ALL ON <table_name>;
-- To Disable a specific trigger on a table
DISABLE TRIGGER <trigger_name> ON <table_name>;
-- To Enable all triggers on a specific table
ENABLE TRIGGER ALL ON <table_name>;
-- To Enable a specific trigger on a table
ENABLE TRIGGER <trigger_name> ON <table_name>;
Um unsere speziellen TR_INS_Sales zu deaktivieren und zu aktivieren Trigger auf die Verkäufe Tabelle verwenden wir die folgenden Skripte:
-- To Disable TR_INS_Sales trigger on Sales table
DISABLE TRIGGER TR_INS_Sales ON Sales;
-- To Enable TR_INS_Sales trigger on Sales table
ENABLE TRIGGER TR_INS_Sales ON Sales;
So haben wir gelernt, wie man DROP macht , DEAKTIVIEREN und AKTIVIEREN löst aus. Ich lösche 3 vorhandene Trigger und erstelle einen einzigen Trigger, der alle 3 Operationen oder das Einfügen, Aktualisieren und Löschen mit dem folgenden Skript abdeckt:
DROP TRIGGER TR_INS_Sales
DROP TRIGGER TR_UPD_Sales
DROP TRIGGER TR_DEL_Sales
GO
CREATE TRIGGER TR_INS_UPD_DEL_Sales ON Sales
FOR INSERT, UPDATE, DELETE
AS
BEGIN
IF (SELECT COUNT (*) FROM deleted) = 0
BEGIN
INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
SELECT SalesId
,SalesDate
,Itemcount
,price
,'INSERT'
FROM inserted
END
ELSE IF (SELECT COUNT (*) FROM inserted) = 0
BEGIN
INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
SELECT SalesId
,SalesDate
,Itemcount
,price
,'DELETE'
FROM deleted
END
ELSE IF (UPDATE (SalesDate) OR UPDATE (ItemCount) OR UPDATE (Price))
BEGIN
INSERT INTO SalesHistory(SalesId,SalesDate,Itemcount,price,ChangeType)
SELECT SalesId
,SalesDate
,Itemcount
,price
,'UPDATE'
FROM inserted
END
END
GO
Die einzelne Triggererstellung war erfolgreich. Wir haben Logik verwendet, um die Operation anhand der eingefügten und gelöschten Tabellen zu identifizieren.
Bei der INSERT-Operation wird die gelöschte Tabelle nicht gefüllt. Beim DELETE-Vorgang wird die eingefügte Tabelle nicht gefüllt. Wir können diese Operationen leicht identifizieren. Wenn diese beiden Bedingungen nicht übereinstimmen, handelt es sich um eine UPDATE-Operation, und wir können eine einfache ELSE-Anweisung verwenden.
Ich habe das UPDATE() verwendet Funktion, um zu zeigen, wie es funktioniert. Wenn für diese Spalten Aktualisierungen vorhanden wären, würde die Auslöseraktion UPDATE ausgelöst. Wir können auch COLUMNS_UPDATED() verwenden Funktion, die wir bereits besprochen haben, um auch eine UPDATE-Operation zu identifizieren.
Testen wir unseren neuen Trigger, indem wir einen neuen Datensatz einfügen:
INSERT INTO Sales(SalesDate,Itemcount,price)
VALUES ('2021-04-01', 4, 400);
Verifizieren von Aufzeichnungen über die Verkäufe und SalesHistory Tabellen zeigt Daten wie folgt:
Versuchen wir, SalesId =2 zu aktualisieren Aufzeichnung:
UPDATE Sales
SET price = 250
WHERE SalesId = 2;
Lassen Sie uns ein DELETE-Skript über dieses Verfahren auf SalesId =4 ausprobieren Aufzeichnung:
DELETE FROM Sales
WHERE SalesId = 4;
Wie wir feststellen können, ist SalesId =4 wurde aus den Verkäufen gelöscht Tabelle, da dies ein FOR ist oder NACH auslösen, wodurch der DELETE-Vorgang bei den Verkäufen erfolgreich ist Tabelle und fügen Sie dann einen Datensatz in die SalesHistory ein Tabelle.
Zweck von DML-Triggern
DML-Trigger dienen effektiv für die folgenden Szenarien:
- Verfolgen Sie historische Änderungen von INSERT-, UPDATE- und DELETE-Vorgängen in einer bestimmten Tabelle.
- Auditieren Sie die DML-Ereignisse, die in einer Tabelle stattfinden, ohne die Auditing-Aktivität den Benutzern offenzulegen.
- Verhindern Sie DML-Änderungen an einer Tabelle über INSTEAD OF auslösen und Benutzer mit einer bestimmten Fehlermeldung warnen.
- Senden Sie Benachrichtigungen an Zielpersonen, wenn Sie vordefinierte Bedingungen erfüllen.
- Starten Sie den SQL Server-Agent-Job oder einen anderen Prozess, wenn eine vordefinierte Bedingung erreicht wird.
Und Sie können sie für alle anderen Geschäftslogikanforderungen verwenden, die Sie mit T-SQL-Anweisungen implementieren können.
Schlussfolgerung
Der DML-Triggertext ähnelt der gespeicherten Prozedur. Wir können jede erforderliche Geschäftslogik implementieren, aber wir müssen beim Schreiben dieser Logik vorsichtig sein, um potenzielle Probleme zu vermeiden.
Obwohl SQL Server die Erstellung mehrerer Trigger für eine einzelne Tabelle unterstützt, ist es besser, sie zu einem einzigen Trigger zu konsolidieren. Auf diese Weise können Sie Auslöser einfach warten und Fehler schneller beheben. Wenn DML-Trigger zu Auditzwecken implementiert werden, stellen Sie sicher, dass SET NOCOUNT ON Option effektiv genutzt wird.
Im nächsten Artikel untersuchen wir DDL-Trigger und Logon-Trigger.