Freigeben über


Erstellen von geschachtelten Triggern

Sowohl DML- als auch DDL-Trigger werden geschachtelt, wenn ein Trigger eine Aktion ausführt, die einen anderen Trigger initiiert. Diese Aktionen können andere Trigger initiieren usw. DML- und DDL-Trigger können bis zu 32 Ebenen geschachtelt werden. Sie können steuern, ob AFTER-Trigger über die Geschachtelte Serverkonfigurationsoption geschachtelt werden können. ANSTELLE VON Triggern (nur DML-Trigger können ANSTELLE VON Triggern) unabhängig von dieser Einstellung geschachtelt werden.

Hinweis

Jeder Verweis auf verwalteten Code aus einem Transact-SQL Trigger zählt als eine Ebene für die 32-Ebenen-Schachtelungsgrenze. Methoden, die aus verwaltetem Code aufgerufen werden, zählen nicht für diesen Grenzwert.

Wenn geschachtelte Trigger zulässig sind und ein Trigger in der Kette eine Endlosschleife startet, wird die Schachtelungsebene überschritten und der Trigger beendet.

Sie können geschachtelte Trigger verwenden, um nützliche Housekeepingfunktionen auszuführen, z. B. das Speichern einer Sicherungskopie von Zeilen, die von einem vorherigen Trigger betroffen sind. Sie können z. B. einen Trigger PurchaseOrderDetail erstellen, der eine Sicherungskopie der Zeilen speichert, die PurchaseOrderDetail der delcascadetrig Trigger gelöscht hat. Mit dem delcascadetrig tatsächlichen Auslöser löscht das Löschen PurchaseOrderID von PurchaseOrderHeader 1965 die entsprechende Zeile oder Zeile aus PurchaseOrderDetail. Zum Speichern der Daten können Sie einen DELETE-Trigger PurchaseOrderDetail erstellen, der die gelöschten Daten in einer anderen separat erstellten Tabelle speichert. del_save Beispiel:

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

Es wird nicht empfohlen, geschachtelte Trigger in einer reihenfolgeabhängigen Sequenz zu verwenden. Verwenden Sie separate Trigger, um Datenänderungen zu überlappen.

Hinweis

Da Trigger innerhalb einer Transaktion ausgeführt werden, bricht ein Fehler auf jeder Ebene geschachtelter Trigger die gesamte Transaktion ab, und alle Datenänderungen werden zurückgesetzt. Fügen Sie PRINT-Anweisungen in Ihre Trigger ein, damit Sie bestimmen können, wo der Fehler aufgetreten ist.

Rekursive Trigger

Ein AFTER-Trigger ruft sich nicht rekursiv auf, es sei denn, die RECURSIVE_TRIGGERS Datenbankoption ist festgelegt.

Es gibt zwei Arten von Rekursionen:

  • Direkte Rekursion

    Diese Rekursion tritt auf, wenn ein Trigger ausgelöst wird und eine Aktion ausführt, die denselben Trigger erneut auslöst. Beispielsweise aktualisiert eine Anwendung die Tabelle T3; dies bewirkt, dass Trig3 ausgelöst wird. Trig3 aktualisiert die Tabelle T3 erneut; dies bewirkt, dass Trig3 erneut ausgelöst wird.

    Direkte Rekursion kann auch auftreten, wenn derselbe Trigger erneut aufgerufen wird, jedoch nachdem ein Trigger eines anderen Typs (AFTER oder INSTEAD OF) ausgelöst wurde. Mit anderen Worten, direkte Rekursion eines INSTEAD OF-Triggers kann auftreten, wenn derselbe INSTEAD OF-Trigger ein zweites Mal aufgerufen wird, auch wenn ein oder mehrere AFTER-Trigger dazwischen aufgerufen werden. Ebenso kann die direkte Rekursion eines AFTER-Triggers auftreten, wenn derselbe AFTER-Trigger erneut aufgerufen wird, selbst wenn ein oder mehrere INSTEAD OF-Trigger dazwischen aufgerufen werden. Beispielsweise aktualisiert eine Anwendung die Tabelle T4. Dieses Update bewirkt, dass der INSTEAD OF-Trigger Trig4 ausgelöst wird. Trig4 aktualisiert Tabelle T5. Dieses Update bewirkt, dass AFTER Trig5 ausgelöst wird. Trig5 aktualisiert tabelle T4, und dieses Update bewirkt, dass Trig4 erneut ausgelöst wird. Diese Ereigniskette gilt als direkte Rekursion für Trig4.

  • Indirekte Rekursion

    Diese Rekursion tritt auf, wenn ein Trigger ausgelöst wird und eine Aktion ausführt, die dazu führt, dass ein anderer Trigger desselben Typs (AFTER oder INSTEAD OF) aktiviert wird. Dieser zweite Trigger führt eine Aktion aus, die bewirkt, dass der ursprüngliche Trigger erneut ausgelöst wird. Mit anderen Worten, indirekte Rekursion kann auftreten, wenn ein INSTEAD OF-Trigger ein zweites Mal aufgerufen wird, aber erst, wenn ein anderer INSTEAD OF-Trigger dazwischen aufgerufen wird. Ebenso kann eine indirekte Rekursion auftreten, wenn ein AFTER-Trigger ein zweites Mal aufgerufen wird, aber erst, nachdem zwischendurch ein anderer AFTER-Trigger aufgerufen wurde. Beispielsweise aktualisiert eine Anwendung die Tabelle T1. Dieses Update bewirkt, dass AFTER-Trigger Trig1 ausgelöst wird. Trig1 aktualisiert die Tabelle T2, und dieses Update bewirkt, dass AFTER-Trigger Trig2 ausgelöst wird. Trig2 aktualisiert wiederum die Tabelle T1 , die bewirkt, dass AFTER-Trigger Trig1 erneut ausgelöst wird.

Nur die direkte Rekursion der AFTER-Trigger wird verhindert, wenn die Datenbankoption RECURSIVE_TRIGGERS auf OFF gesetzt ist. Um die indirekte Rekursion von AFTER-Triggern zu deaktivieren, legen Sie auch die Option für geschachtelte Trigger auf 0 fest.

Beispiele

Das folgende Beispiel zeigt die Verwendung rekursiver Trigger zum Lösen einer selbstverweisenden Beziehung (auch als transitive Schließung bezeichnet). Die Tabelle emp_mgr definiert beispielsweise Folgendes:

  • Ein Mitarbeiter (emp) in einem Unternehmen.

  • Der Vorgesetzte für jeden Mitarbeiter (mgr).

  • Die Gesamtzahl der Mitarbeiter in der Organisationsstruktur, die für jeden Mitarbeiter (NoOfReports) gemeldet wird.

Ein rekursiver UPDATE-Trigger kann verwendet werden, um die NoOfReports Spalte up-to-datum beizubehalten, wenn neue Mitarbeiterdatensätze eingefügt werden. Der INSERT-Trigger aktualisiert die NoOfReports-Spalte des Managerdatensatzes, wodurch die NoOfReports-Spalte anderer Datensätze rekursiv innerhalb der Management-Hierarchie aktualisiert wird.

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  

Hier sind die Ergebnisse vor dem Update.

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

Hier sind die Ergebnisse nach dem Update.

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

Um die Option "Geschachtelte Trigger" festzulegen

So legen Sie die RECURSIVE_TRIGGERS-Datenbankoption fest

Siehe auch

CREATE TRIGGER (Transact-SQL)
Konfigurieren der geschachtelten Trigger für die Serverkonfigurationsoption