Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Aplica-se a:SQL Server
Azure SQL Database
Azure SQL Managed Instance
Base de dados SQL no Microsoft Fabric
Os gatilhos DML e DDL são aninhados quando um gatilho executa uma ação que inicia outro gatilho. Essas ações podem iniciar outros gatilhos e assim por diante. Os gatilhos DML e DDL podem ser aninhados em até 32 níveis. Você pode controlar se os gatilhos AFTER podem ser aninhados por meio da opção de configuração do servidor de gatilhos aninhados . Em vez disso, os gatilhos (apenas os gatilhos DML podem ser EM vez DE gatilhos) podem ser aninhados independentemente dessa configuração.
Observação
Qualquer referência a código gerenciado de um gatilho de Transact-SQL conta como um nível em relação ao limite de aninhamento de 32 níveis. Os métodos invocados a partir do código gerenciado não contam para esse limite.
Se gatilhos aninhados forem permitidos e um gatilho na cadeia iniciar um loop infinito, o nível de aninhamento será excedido e o gatilho será encerrado.
Você pode usar gatilhos aninhados para executar funções úteis de limpeza, como armazenar uma cópia de backup de linhas afetadas por um gatilho anterior. Por exemplo, você pode criar um gatilho que PurchaseOrderDetail salva uma cópia de backup das linhas que o gatilho PurchaseOrderDetaildelcascadetrig excluiu. Com o gatilho delcascadetrig em vigor, excluir PurchaseOrderID 1965 de PurchaseOrderHeader exclui a linha ou linhas correspondentes do PurchaseOrderDetail. Para salvar os dados, você pode criar um gatilho DELETE que PurchaseOrderDetail salva os dados excluídos em outra tabela criada separadamente, del_save. Por exemplo:
CREATE TRIGGER Purchasing.savedel
ON Purchasing.PurchaseOrderDetail
FOR DELETE
AS
INSERT del_save
SELECT * FROM deleted;
Não recomendamos o uso de gatilhos aninhados em uma sequência dependente da ordem. Use gatilhos separados para fazer modificações de dados em cascata.
Observação
Como os gatilhos são executados dentro de uma transação, uma falha em qualquer nível de um conjunto de gatilhos aninhados cancela toda a transação e todas as modificações de dados são revertidas. Inclua instruções PRINT em seus gatilhos para que você possa determinar onde a falha ocorreu.
Gatilhos recursivos
Um gatilho AFTER não se chama recursivamente, a menos que a opção de banco de dados RECURSIVE_TRIGGERS esteja definida.
Existem dois tipos de recursão:
Recursão direta
Essa recursão ocorre quando um gatilho é acionado e executa uma ação que faz com que o mesmo gatilho dispare novamente. Por exemplo, um aplicativo atualiza a tabela T3; isso faz com que o gatilho Trig3 dispare. Trig3 atualiza novamente a tabela T3 ; isso faz com que o gatilho Trig3 dispare novamente.
A recursão direta também pode ocorrer quando o mesmo gatilho é chamado novamente, mas depois que um gatilho de um tipo diferente (AFTER ou INSTEAD OF) é chamado. Em outras palavras, a recursão direta de um gatilho EM VEZ DE pode ocorrer quando o mesmo gatilho EM VEZ DE é chamado pela segunda vez, mesmo que um ou mais gatilhos AFTER sejam chamados no meio. Da mesma forma, a recursão direta de um gatilho AFTER pode ocorrer quando o mesmo gatilho AFTER é chamado pela segunda vez, mesmo que um ou mais gatilhos AFTER OF sejam chamados no meio. Por exemplo, um aplicativo atualiza a tabela T4. Esta atualização faz com que em vez de acionar Trig4 disparar. Trig4 atualiza a tabela T5. Esta atualização faz com que o gatilho AFTER Trig5 seja acionado. Trig5 atualiza a tabela T4, e esta atualização faz com que em vez de acionar Trig4 para disparar novamente. Esta cadeia de eventos é considerada recursão direta para Trig4.
Recursão indireta
Essa recursão ocorre quando um gatilho é acionado e executa uma ação que faz com que outro gatilho do mesmo tipo (AFTER ou INSTEAD OF) dispare. Este segundo gatilho executa uma ação que faz com que o gatilho original dispare novamente. Em outras palavras, a recursão indireta pode ocorrer quando um gatilho EM VEZ DE é chamado pela segunda vez, mas não até que outro gatilho EM VEZ DE seja chamado no meio. Da mesma forma, a recursão indireta pode ocorrer quando um gatilho AFTER é chamado pela segunda vez, mas não até que outro gatilho AFTER seja chamado no meio. Por exemplo, um aplicativo atualiza a tabela T1. Esta atualização faz com que o gatilho AFTER Trig1 seja acionado. Trig1 atualiza a tabela T2, e esta atualização faz com que o gatilho AFTER Trig2 dispare. Trig2 por sua vez atualiza a tabela T1 que faz com que o gatilho AFTER Trig1 dispare novamente.
Somente a recursão direta de gatilhos AFTER é impedida quando a opção de banco de dados RECURSIVE_TRIGGERS está definida como OFF. Para desabilitar a recursão indireta de gatilhos AFTER, defina também a opção de servidor de gatilhos aninhados como 0.
Exemplos
O exemplo a seguir mostra o uso de gatilhos recursivos para resolver uma relação de autorreferência (também conhecida como fechamento transitivo). Por exemplo, a tabela emp_mgr define o seguinte:
Um empregado (
emp) numa empresa.O gerente de cada funcionário (
mgr).O número total de funcionários na árvore organizacional relatando a cada funcionário (
NoOfReports).
Um gatilho UPDATE recursivo pode ser usado para manter a NoOfReports coluna up-to-date à medida que novos registros de funcionários são inseridos. O gatilho INSERT atualiza a NoOfReports coluna do registro do gerente, que atualiza recursivamente a NoOfReports coluna de outros registros na hierarquia de gerenciamento.
USE AdventureWorks2022;
GO
-- Turn recursive triggers ON in the database.
ALTER DATABASE AdventureWorks2022
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
Aqui estão os resultados antes da atualização.
emp mgr NoOfReports
------------------------------ ----------------------------- -----------
Alice Harry 2
Dave Joe 0
Harry NULL 1
Joe Alice 1
Paul Alice 0
Aqui estão os resultados após a atualização.
emp mgr NoOfReports
------------------------------ ----------------------------- -----------
Alice Harry 2
Dave Harry 0
Harry NULL 2
Joe Alice 0
Paul Alice 0
Para definir a opção de gatilhos aninhados
Para definir a opção RECURSIVE_TRIGGERS banco de dados
Ver também
CRIAR GATILHO (Transact-SQL)
Configurar os gatilhos aninhados Opção de Configuração do Servidor