Creazione di trigger annidatiCreate Nested Triggers

Entrambi i trigger DML e DDL vengono nidificati quando un trigger esegue un'operazione che ne avvia un altro.Both DML and DDL triggers are nested when a trigger performs an action that initiates another trigger. Tali operazioni possono quindi avviare altri trigger e così via.These actions can initiate other triggers, and so on. I trigger DML e DDL possono essere nidificati fino a un massimo di 32 livelli.DML and DDL triggers can be nested up to 32 levels. Per gestire la nidificazione dei trigger AFTER, utilizzare l'opzione di configurazione del server nested triggers .You can control whether AFTER triggers can be nested through the nested triggers server configuration option. I trigger INSTEAD OF (solo DML) possono essere nidificati indipendentemente da questa impostazione.INSTEAD OF triggers (only DML triggers can be INSTEAD OF triggers) can be nested regardless of this setting.

Nota

Qualsiasi riferimento a codice gestito da un trigger Transact-SQLTransact-SQL viene conteggiato come un unico livello rispetto al limite dei 32 livelli di nidificazione.Any reference to managed code from a Transact-SQLTransact-SQL trigger counts as one level against the 32-level nesting limit. I metodi richiamati da codice gestito non vengono inclusi nel conteggio per questo limite.Methods invoked from within managed code do not count against this limit.

Se è consentito l'utilizzo di trigger nidificati e un trigger della catena avvia un ciclo infinito, il livello di nidificazione viene superato e il trigger viene interrotto.If nested triggers are allowed and a trigger in the chain starts an infinite loop, the nesting level is exceeded and the trigger terminates.

È possibile utilizzare i trigger nidificati per eseguire funzioni di manutenzione, utili quali l'archiviazione di una copia di backup delle righe interessate da un trigger precedente.You can use nested triggers to perform useful housekeeping functions such as storing a backup copy of rows affected by a previous trigger. È ad esempio possibile creare un trigger su PurchaseOrderDetail per salvare una copia di backup delle righe di PurchaseOrderDetail eliminate dal trigger delcascadetrig .For example, you can create a trigger on PurchaseOrderDetail that saves a backup copy of the PurchaseOrderDetail rows that the delcascadetrig trigger deleted. Se il trigger delcascadetrig è attivo, l'eliminazione di PurchaseOrderID 1965 dalla tabella PurchaseOrderHeader implica l'eliminazione della riga o delle righe corrispondenti da PurchaseOrderDetail.With the delcascadetrig trigger in effect, deleting PurchaseOrderID 1965 from PurchaseOrderHeader deletes the corresponding row or rows from PurchaseOrderDetail. Per salvare i dati eliminati in un'altra tabella creata separatamente denominata PurchaseOrderDetail , creare un trigger DELETE su del_save.To save the data, you can create a DELETE trigger on PurchaseOrderDetail that saves the deleted data into another separately created table, del_save. Esempio:For example:

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

È consigliabile non utilizzare trigger nidificati in una sequenza dipendente dall'ordinamento.We do not recommend using nested triggers in an order-dependent sequence. Utilizzare trigger distinti per eseguire modifiche a catena dei dati.Use separate triggers to cascade data modifications.

Nota

Poiché i trigger vengono eseguiti all'interno di una transazione, un errore a qualsiasi livello di un set di trigger nidificati annulla l'intera transazione con conseguente rollback di tutte le modifiche apportate ai dati.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. Per determinare la posizione in cui si è verificato l'errore, includere nei trigger le istruzioni PRINT.Include PRINT statements in your triggers so that you can determine where the failure has occurred.

Trigger ricorsiviRecursive Triggers

Un trigger AFTER non chiama se stesso in modo ricorsivo a meno che non sia stata impostata l'opzione di database RECURSIVE_TRIGGERS.An AFTER trigger does not call itself recursively unless the RECURSIVE_TRIGGERS database option is set.

Esistono due tipi di ricorsione:There are two types of recursion:

  • Ricorsione direttaDirect recursion

    Questo tipo di ricorsione si verifica quando un trigger viene attivato ed esegue un'azione che attiva nuovamente lo stesso trigger.This recursion occurs when a trigger fires and performs an action that causes the same trigger to fire again. Ad esempio, un'applicazione aggiorna la tabella T3che attiva il trigger Trig3 .For example, an application updates table T3; this causes trigger Trig3 to fire. Trig3 aggiorna nuovamente la tabella T3 , che attiva nuovamente il trigger Trig3 .Trig3 updates table T3 again; this causes trigger Trig3 to fire again.

    La ricorsione diretta può inoltre verificarsi quando lo stesso trigger viene richiamato, ma solo dopo la chiamata di un trigger di tipo diverso (AFTER o 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. In altri termini, la ricorsione diretta di un trigger INSTEAD OF può verificarsi quando lo stesso trigger INSTEAD OF viene chiamato per la seconda volta, anche se nel frattempo sono stati chiamati uno o più trigger AFTER.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. Analogamente, la ricorsione diretta di un trigger AFTER può verificarsi quando lo stesso trigger AFTER viene chiamato per la seconda volta, anche se nel frattempo sono stati chiamati uno o più trigger INSTEAD OF.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. Ad esempio, un'applicazione aggiorna la tabella T4.For example, an application updates table T4. L'aggiornamento attiva il trigger INSTEAD OF Trig4 .This update causes INSTEAD OF trigger Trig4 to fire. Trig4 aggiorna la tabella T5.Trig4 updates table T5. L'aggiornamento attiva il trigger AFTER Trig5 .This update causes AFTER trigger Trig5 to fire. Trig5 aggiorna la tabella T4e questa operazione attiva nuovamente il trigger INSTEAD OF Trig4 .Trig5 updates table T4, and this update causes INSTEAD OF trigger Trig4 to fire again. Questa catena di eventi costituisce una ricorsione diretta per il trigger Trig4.This chain of events is considered direct recursion for Trig4.

  • Ricorsione indirettaIndirect recursion

    Questo tipo di ricorsione si verifica quando un trigger viene attivato ed esegue un'azione che attiva un altro trigger dello stesso tipo (AFTER o 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. Il secondo esegue un'operazione che implica nuovamente l'attivazione del trigger originale.This second trigger performs an action that causes the original trigger to fire again. In altri termini, la ricorsione indiretta può verificarsi quando un trigger INSTEAD OF viene chiamato per la seconda volta, ma non prima della chiamata di un altro trigger INSTEAD OF.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. Analogamente, la ricorsione indiretta può verificarsi quando un trigger AFTER viene chiamato per la seconda volta, ma non prima della chiamata di un altro trigger AFTER.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. Ad esempio, un'applicazione aggiorna la tabella T1.For example, an application updates table T1. L'aggiornamento attiva il trigger AFTER Trig1 .This update causes AFTER trigger Trig1 to fire. Trig1 aggiorna la tabella T2e questa operazione attiva il trigger AFTER Trig2 .Trig1 updates table T2, and this update causes AFTER trigger Trig2 to fire. Trig2 aggiorna, a sua volta, la tabella T1 che attiva nuovamente il trigger AFTER Trig1 .Trig2 in turn updates table T1 that causes AFTER trigger Trig1 to fire again.

    Se l'opzione di database RECURSIVE_TRIGGERS è impostata su OFF, viene evitata solo la ricorsione diretta dei trigger AFTER.Only direct recursion of AFTER triggers is prevented when the RECURSIVE_TRIGGERS database option is set to OFF. Per disabilitare la ricorsione indiretta dei trigger AFTER, impostare su 0 anche l'opzione del server nested triggers.To disable indirect recursion of AFTER triggers, also set the nested triggers server option to 0.

EsempiExamples

Nell'esempio seguente viene illustrato l'utilizzo dei trigger ricorsivi per risolvere una relazione autoreferenziale, nota anche come chiusura transitiva.The following example shows using recursive triggers to solve a self-referencing relationship (also known as transitive closure). Ad esempio, nella tabella emp_mgr vengono definiti gli elementi seguenti:For example, the table emp_mgr defines the following:

  • Il dipendente (emp) di una società.An employee (emp) in a company.

  • Il responsabile di ciascun dipendente (mgr).The manager for each employee (mgr).

  • Il numero totale di dipendenti nell'albero organizzativo di cui ogni dipendente è responsabile (NoOfReports).The total number of employees in the organizational tree reporting to each employee (NoOfReports).

    È possibile utilizzare un trigger UPDATE ricorsivo per aggiornare la colonna NoOfReports quando vengono inseriti i record di nuovi dipendenti.A recursive UPDATE trigger can be used to keep the NoOfReports column up-to-date as new employee records are inserted. Il trigger INSERT aggiorna la colonna NoOfReports del record del responsabile che aggiorna in modo ricorsivo la colonna NoOfReports degli altri record fino ai livelli più alti dell'organigramma.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  

Risultati prima dell'aggiornamento.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  

Risultati dopo l'aggiornamento.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  

Per impostare l'opzione nested triggersTo set the nested triggers option

Vedere ancheSee Also

CREATE TRIGGER (Transact-SQL) CREATE TRIGGER (Transact-SQL)
Configurare l'opzione di configurazione del server nested triggersConfigure the nested triggers Server Configuration Option