Erstellen von geschachtelten TriggernCreate Nested Triggers

Gilt für: JaSQL Server JaAzure SQL-Datenbank NeinAzure Synapse Analytics (SQL DW) NeinParallel Data Warehouse APPLIES TO: yesSQL Server yesAzure SQL Database noAzure Synapse Analytics (SQL DW) noParallel Data Warehouse

Sowohl DML-Trigger als auch DDL-Trigger werden geschachtelt, wenn ein Trigger eine Aktion ausführt, die einen anderen Trigger auslöst.Both DML and DDL triggers are nested when a trigger performs an action that initiates another trigger. Diese Aktionen können andere Trigger auslösen usw.These actions can initiate other triggers, and so on. DML- und DDL-Trigger können bis auf 32 Ebenen geschachtelt werden.DML and DDL triggers can be nested up to 32 levels. Sie können über die Geschachtelte Trigger -Serverkonfigurationsoption steuern, ob AFTER-Trigger geschachtelt werden können.You can control whether AFTER triggers can be nested through the nested triggers server configuration option. INSTEAD OF-Trigger (nur DML-Trigger können INSTEAD OF-Trigger sein) können unabhängig von dieser Einstellung geschachtelt werden.INSTEAD OF triggers (only DML triggers can be INSTEAD OF triggers) can be nested regardless of this setting.

Hinweis

Alle Verweise auf verwalteten Code aus einem Trigger von Transact-SQLTransact-SQL zählen als eine Ebene hinsichtlich der Schachtelungsgrenze von 32 Ebenen.Any reference to managed code from a Transact-SQLTransact-SQL trigger counts as one level against the 32-level nesting limit. Methoden, die aus verwaltetem Code aufgerufen werden, werden nicht mitgezählt.Methods invoked from within managed code do not count against this limit.

Wenn geschachtelte Trigger zulässig sind und ein Trigger in der Kette eine Endlosschleife einleitet, wird die Anzahl der maximal zulässigen Schachtelungsebenen überschritten und der Trigger demzufolge beendet.If nested triggers are allowed and a trigger in the chain starts an infinite loop, the nesting level is exceeded and the trigger terminates.

Sie können geschachtelte Trigger verwenden, um nützliche Verwaltungsfunktionen durchzuführen, wie z. B. das Speichern einer Sicherungskopie von Zeilen, die von einem vorherigen Trigger betroffen sind.You can use nested triggers to perform useful housekeeping functions such as storing a backup copy of rows affected by a previous trigger. Es ist beispielsweise möglich, einen Trigger für PurchaseOrderDetail zu erstellen, der eine Sicherungskopie der PurchaseOrderDetail -Zeilen speichert, die vom delcascadetrig -Trigger gelöscht wurden.For example, you can create a trigger on PurchaseOrderDetail that saves a backup copy of the PurchaseOrderDetail rows that the delcascadetrig trigger deleted. Wenn der delcascadetrig -Trigger wirksam ist, führt das Löschen von PurchaseOrderID 1965 aus PurchaseOrderHeader dazu, dass die entsprechende(n) Zeile(n) aus PurchaseOrderDetailgelöscht werden.With the delcascadetrig trigger in effect, deleting PurchaseOrderID 1965 from PurchaseOrderHeader deletes the corresponding row or rows from PurchaseOrderDetail. Zum Speichern der Daten erstellen Sie einen DELETE-Trigger für PurchaseOrderDetail , der die gelöschten Daten in einer getrennt erstellten Tabelle, del_save, speichert.To save the data, you can create a DELETE trigger on PurchaseOrderDetail that saves the deleted data into another separately created table, del_save. Beispiel:For example:

CREATE TRIGGER Purchasing.savedel  
   ON Purchasing.PurchaseOrderDetail  
FOR DELETE  
AS  
   INSERT del_save;  
   SELECT * FROM deleted;  

Das Verwenden geschachtelter Trigger wird nicht für eine Sequenz empfohlen, in der die Reihenfolge wichtig ist.We do not recommend using nested triggers in an order-dependent sequence. Verwenden Sie getrennte Trigger, um Datenänderungen kaskadierend weiterzugeben.Use separate triggers to cascade data modifications.

Hinweis

Da Trigger innerhalb einer Transaktion ausgeführt werden, führt ein Fehler auf einer beliebigen Ebene einer Reihe geschachtelter Trigger zum Abbruch der gesamten Transaktion und zum Rollback für alle Datenänderungen.Because triggers execute within a transaction, a failure at any level of a set of nested triggers cancels the entire transaction, and all data modifications are rolled back. Fügen Sie PRINT-Anweisungen in die Trigger ein, sodass Sie ermitteln können, wo der Fehler aufgetreten ist.Include PRINT statements in your triggers so that you can determine where the failure has occurred.

Rekursive TriggerRecursive Triggers

Ein AFTER-Trigger kann sich nur dann rekursiv aufrufen, wenn die Datenbankoption RECURSIVE_TRIGGERS festgelegt wurde.An AFTER trigger does not call itself recursively unless the RECURSIVE_TRIGGERS database option is set.

Die folgenden zwei Rekursionsarten stehen zur Verfügung:There are two types of recursion:

  • Direkte RekursionDirect recursion

    Diese Rekursion tritt auf, wenn ein Trigger ausgelöst wird und eine Aktion ausführt, die das erneute Auslösen desselben Triggers verursacht.This recursion occurs when a trigger fires and performs an action that causes the same trigger to fire again. Eine Anwendung aktualisiert z. B. die T3-Tabelle, wodurch der Trig3 -Trigger ausgelöst wird.For example, an application updates table T3; this causes trigger Trig3 to fire. Trig3 aktualisiert T3 erneut, sodass der Trig3 -Trigger erneut ausgelöst wird.Trig3 updates table T3 again; this causes trigger Trig3 to fire again.

    Die direkte Rekursion kann auch auftreten, wenn derselbe Trigger erneut aufgerufen wird, jedoch erst nach dem Aufruf eines weiteren Triggers, der einen anderen Typ aufweist (AFTER oder INSTEAD OF).Direct recursion can also occur when the same trigger is called again, but after a trigger of a different type (AFTER or INSTEAD OF) is called. Mit anderen Worten: Die direkte Rekursion eines INSTEAD OF-Triggers kann auftreten, wenn derselbe INSTEAD OF-Trigger ein zweites Mal aufgerufen wird, auch wenn zwischendurch mindestens ein AFTER-Trigger aufgerufen wird.In other words, direct recursion of an INSTEAD OF trigger can occur when the same INSTEAD OF trigger is called for a second time, even if one or more AFTER triggers are called in between. Auf gleiche Weise kann die direkte Rekursion eines AFTER-Triggers auftreten, wenn derselbe AFTER-Trigger ein zweites Mal aufgerufen wird, auch wenn zwischendurch mindestens ein INSTEAD OF-Trigger aufgerufen wird.Likewise, direct recursion of an AFTER trigger can occur when the same AFTER trigger is called for a second time, even if one or more INSTEAD OF triggers are called in between. Beispielsweise aktualisiert eine Anwendung Tabelle T4.For example, an application updates table T4. Durch dieses Update wird das Auslösen von INSTEAD OF-Trigger Trig4 verursacht.This update causes INSTEAD OF trigger Trig4 to fire. Trig4 aktualisiert Tabelle T5.Trig4 updates table T5. Durch dieses Update wird das Auslösen von AFTER-Trigger Trig5 verursacht.This update causes AFTER trigger Trig5 to fire. Trig5 aktualisiert wiederum Tabelle T4. Dieses Update verursacht erneut das Auslösen von INSTEAD OF-Trigger Trig4 .Trig5 updates table T4, and this update causes INSTEAD OF trigger Trig4 to fire again. Diese Kette von Ereignissen wird als direkte Rekursion für Trig4betrachtet.This chain of events is considered direct recursion for Trig4.

  • Indirekte RekursionIndirect recursion

    Diese Rekursion tritt auf, wenn ein Trigger ausgelöst wird, der eine Aktion ausführt, die das Auslösen eines anderen Triggers des gleichen Typs verursacht (AFTER oder INSTEAD OF).This recursion occurs when a trigger fires and performs an action that causes another trigger of the same type (AFTER or INSTEAD OF) to fire. Dieser zweite Trigger führt eine Aktion aus, die das erneute Auslösen des ursprünglichen Triggers bewirkt.This second trigger performs an action that causes the original trigger to fire again. Mit anderen Worten: Die indirekte Rekursion tritt auf, wenn ein INSTEAD OF-Trigger ein zweites Mal aufgerufen wird, jedoch erst, wenn in der Zwischenzeit ein anderer INSTEAD OF-Trigger aufgerufen wird.In other words, indirect recursion can occur when an INSTEAD OF trigger is called for a second time, but not until another INSTEAD OF trigger is called in between. Die indirekte Rekursion kann gleichermaßen auftreten, wenn ein AFTER-Trigger ein zweites Mal aufgerufen wird, jedoch erst, wenn in der Zwischenzeit ein anderer AFTER-Trigger aufgerufen wird.Likewise, indirect recursion can occur when an AFTER trigger is called for a second time, but not until another AFTER trigger is called in between. Beispielsweise aktualisiert eine Anwendung Tabelle T1.For example, an application updates table T1. Durch dieses Update wird das Auslösen von AFTER-Trigger Trig1 verursacht.This update causes AFTER trigger Trig1 to fire. Trig1 aktualisiert Tabelle T2. Dieses Update verursacht wiederum das Auslösen von AFTER-Trigger Trig2 .Trig1 updates table T2, and this update causes AFTER trigger Trig2 to fire. Trig2 aktualisiert nun wiederum Tabelle T1 , wodurch der AFTER-Trigger Trig1 erneut ausgelöst wird.Trig2 in turn updates table T1 that causes AFTER trigger Trig1 to fire again.

Es wird nur die direkte Rekursion von AFTER-Triggern verhindert, wenn die Datenbankoption RECURSIVE_TRIGGERS auf OFF festgelegt ist.Only direct recursion of AFTER triggers is prevented when the RECURSIVE_TRIGGERS database option is set to OFF. Sie müssen auch die Geschachtelte Trigger -Serveroption auf 0festlegen, um die indirekte Rekursion von AFTER-Triggern zu deaktivieren.To disable indirect recursion of AFTER triggers, also set the nested triggers server option to 0.

BeispieleExamples

Das folgende Beispiel zeigt die Verwendung rekursiver Trigger zum Auflösen einer auf sich selbst verweisenden Beziehung (auch als transitiver Abschluss bezeichnet).The following example shows using recursive triggers to solve a self-referencing relationship (also known as transitive closure). Die emp_mgr -Tabelle definiert z. B. Folgendes:For example, the table emp_mgr defines the following:

  • Einen Angestellten (emp) in einem Unternehmen.An employee (emp) in a company.

  • Den Vorgesetzten jedes Angestellten (mgr).The manager for each employee (mgr).

  • Die Gesamtzahl der Angestellten in der Hierarchie, die jedem einzelnen Vorgesetzten unterstellt sind (NoOfReports).The total number of employees in the organizational tree reporting to each employee (NoOfReports).

Mithilfe eines rekursiven UPDATE-Triggers kann die NoOfReports -Spalte auf dem aktuellen Stand gehalten werden, wenn neue Angestelltendatensätze eingefügt werden.A recursive UPDATE trigger can be used to keep the NoOfReports column up-to-date as new employee records are inserted. Der INSERT-Trigger aktualisiert die NoOfReports -Spalte für den Datensatz des Vorgesetzten, wodurch rekursiv die NoOfReports -Spalte anderer Datensätze auf den höheren Hierarchieebenen aktualisiert wird.The INSERT trigger updates the NoOfReports column of the manager record, which recursively updates the NoOfReports column of other records up the management hierarchy.

USE AdventureWorks2012;  
GO  
-- Turn recursive triggers ON in the database.  
ALTER DATABASE AdventureWorks2012  
   SET RECURSIVE_TRIGGERS ON;  
GO  
CREATE TABLE dbo.emp_mgr (  
   emp char(30) PRIMARY KEY,  
    mgr char(30) NULL FOREIGN KEY REFERENCES emp_mgr(emp),  
    NoOfReports int DEFAULT 0  
);  
GO  
CREATE TRIGGER dbo.emp_mgrins ON dbo.emp_mgr  
FOR INSERT  
AS  
DECLARE @e char(30), @m char(30);  
DECLARE c1 CURSOR FOR  
   SELECT emp_mgr.emp  
   FROM   emp_mgr, inserted  
   WHERE emp_mgr.emp = inserted.mgr;  
  
OPEN c1;  
FETCH NEXT FROM c1 INTO @e;  
WHILE @@fetch_status = 0  
BEGIN  
   UPDATE dbo.emp_mgr  
   SET emp_mgr.NoOfReports = emp_mgr.NoOfReports + 1 -- Add 1 for newly  
   WHERE emp_mgr.emp = @e ;                           -- added employee.  
  
   FETCH NEXT FROM c1 INTO @e;  
END  
CLOSE c1;  
DEALLOCATE c1;  
GO  
-- This recursive UPDATE trigger works assuming:  
--   1. Only singleton updates on emp_mgr.  
--   2. No inserts in the middle of the org tree.  
CREATE TRIGGER dbo.emp_mgrupd ON dbo.emp_mgr FOR UPDATE  
AS  
IF UPDATE (mgr)  
BEGIN  
   UPDATE dbo.emp_mgr  
   SET emp_mgr.NoOfReports = emp_mgr.NoOfReports + 1 -- Increment mgr's  
   FROM inserted                            -- (no. of reports) by  
   WHERE emp_mgr.emp = inserted.mgr;         -- 1 for the new report.  
  
   UPDATE dbo.emp_mgr  
   SET emp_mgr.NoOfReports = emp_mgr.NoOfReports - 1 -- Decrement mgr's  
   FROM deleted                             -- (no. of reports) by 1  
   WHERE emp_mgr.emp = deleted.mgr;          -- for the new report.  
END  
GO  
-- Insert some test data rows.  
INSERT dbo.emp_mgr(emp, mgr) VALUES  
    ('Harry', NULL)  
    ,('Alice', 'Harry')  
    ,('Paul', 'Alice')  
    ,('Joe', 'Alice')  
    ,('Dave', 'Joe');  
GO  
SELECT emp,mgr,NoOfReports  
FROM dbo.emp_mgr;  
GO  
-- Change Dave's manager from Joe to Harry  
UPDATE dbo.emp_mgr SET mgr = 'Harry'  
WHERE emp = 'Dave';  
GO  
SELECT emp,mgr,NoOfReports FROM emp_mgr;  
  
GO  

Im Folgenden sehen Sie die Ergebnisse vor dem Update.Here are the results before the update.

emp                            mgr                           NoOfReports  
------------------------------ ----------------------------- -----------  
Alice                          Harry                          2  
Dave                           Joe                            0  
Harry                          NULL                           1  
Joe                            Alice                          1  
Paul                           Alice                          0  

Im Folgenden sehen Sie die Ergebnisse nach dem Update.Here are the results after the update.

emp                            mgr                           NoOfReports  
------------------------------ ----------------------------- -----------  
Alice                          Harry                          2  
Dave                           Harry                          0  
Harry                          NULL                           2  
Joe                            Alice                          0  
Paul                           Alice                          0  

So legen Sie die Option für geschachtelte Trigger festTo set the nested triggers option

So legen Sie die Datenbankoption RECURSIVE_TRIGGERS festTo set the RECURSIVE_TRIGGERS database option

Weitere InformationenSee Also

CREATE TRIGGER (Transact-SQL) CREATE TRIGGER (Transact-SQL)
Konfigurieren der Serverkonfigurationsoption Geschachtelte TriggerConfigure the nested triggers Server Configuration Option