Como identificar a query que disparou uma trigger de DML numa tabela? Li essa dúvida num grupo do Telegram e resolvi escrever um artigo sobre isso.
Introduction
Como vocês sabem, existem várias soluções para se implementar um log de auditoria com as alterações de dados em uma determinada tabela:
- SQL Server – Como monitorar e auditar alterações de dados em tabelas utilizando Change Data Capture (CDC)
- SQL Server 2016 – Como “viajar no tempo” utilizando o recurso Temporal Tables
- SQL Server – Como criar um histórico de alterações de dados para suas tabelas (logs para auditoria)
- Auditing in SQL Server (Server Audit)
Uma das soluções mais utilizadas para isso, é a utilização de triggers de DML (Saiba como implementar isso clicando aqui)
Em alguns cenários, é importante identificar qual a consulta que acabou disparando a trigger para talvez identificar a origem dos dados que estão sendo inseridos a partir do SQL. E é isso que aprenderemos como fazer nesse post.
Caso você queira mais detalhes da origem desse comando e identificar toda a cadeia de execução da trigger, sugiro a leitura do artigo SQL Server – Como identificar e monitorar a execução de triggers.
Creating the test base
Para a demonstração dos códigos desse artigo, vou compartilhar com vocês o script que utilizei para montar essa tabela e a trigger utilizada para auditar as alterações. Vou utilizar o mesmo exemplo do artigo SQL Server – Como criar um histórico de alterações de dados para suas tabelas (logs para auditoria).
Criação das tabelas
Clique aqui para visualizar código da criação das tabelas
Criação da trigger:
Clique aqui para visualizar o código da trigger
Faço algumas alterações na tabela original:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
INSERT INTO dbo.Cliente VALUES ('Bartolomeu', '1975-05-28', 6158.74) UPDATE dbo.Cliente SET Salario = Salario * 1.5 WHERE Name = 'Bartolomeu' DELETE FROM dbo.Cliente WHERE Name = 'André' UPDATE dbo.Cliente SET Salario = Salario * 1.1 WHERE Id_Cliente = 2 UPDATE dbo.Cliente SET Salario = 10, Name = 'Judas Iscariodes', Data_Nascimento = '06/06/2066' WHERE Id_Cliente = 1 |
E podemos ver que a auditoria está funcionando conforme o esperado:
Como identificar a query que disparou a trigger
Agora descobriremos como identificar a query que disparou a trigger.
Para isso, vamos alterar a trigger e incluir o comando INPUTBUFFER para capturar a query e armazenar essa informação na tabela de log.
A sintaxe de utilização do comando é assim:
1 2 3 4 5 6 7 8 9 10 11 12 |
DECLARE @SqlQuery VARCHAR(MAX) DECLARE @TableSqlQuery TABLE ( EventType NVARCHAR(30), [Parameters] INT, EventInfo NVARCHAR(MAX) ) INSERT INTO @TableSqlQuery EXEC('DBCC INPUTBUFFER(@@SPID)') SET @SqlQuery = (SELECT TOP(1) EventInfo FROM @TableSqlQuery) |
Adicionaremos o campo que armazenará a query na tabela:
1 |
ALTER TABLE dbo.Cliente_Log ADD Ds_Query VARCHAR(MAX) |
E agora alteramos a trigger:
Clique aqui para visualizar código da trigger
E vamos testar novamente executando o comando abaixo:
1 2 3 4 5 6 7 8 |
INSERT INTO dbo.Cliente VALUES('Dirceu', '1987-05-28', 0) INSERT INTO dbo.Cliente SELECT 'Resende' AS Name, '1987-05-28' AS Dt_Nascimento, 9999 AS Vl_Salario |
Como as 2 instruções SQL foram executadas juntas, no mesmo batch, o comando INPUTBUFFER capturou os 2 comandos de uma vez. Se eu tentar executar novamente, mas utilizando um GO para separar os blocos ou mesmo, executando separadamente, podemos observar que a trigger agora vai identificar corretamente os comandos de cada instrução:
1 2 3 4 5 6 7 8 9 10 |
INSERT INTO dbo.Cliente VALUES('Dirceu - Teste 2', '1987-05-28', 0) GO INSERT INTO dbo.Cliente SELECT 'Resende - Teste 2' AS Name, '1987-05-28' AS Dt_Nascimento, 9999 AS Vl_Salario GO |
E se tiver outra trigger, em outra tabela, que está alterando a tabela Cliente e você não está conseguindo identificar de onde vem esse comando?
Primeiro, criaremos uma tabela com dados de funcionários:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
IF (OBJECT_ID('dbo.Funcionario') IS NOT NULL) DROP TABLE dbo.Funcionario GO CREATE TABLE dbo.Funcionario ( Id_Funcionario INT IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED, Name VARCHAR(100) ) GO INSERT INTO dbo.Funcionario ( Name ) VALUES ( 'Dirceu' ), ('Resende') |
Agora criarei uma trigger nessa nova tabela que atualiza a tabela Cliente caso o cliente e o funcionário tenham o mesmo nome:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
CREATE TRIGGER trgFuncionario ON dbo.Funcionario -- Tabela que a trigger será associada AFTER UPDATE AS BEGIN SET NOCOUNT ON UPDATE A SET A.Name = B.Name FROM dbo.Cliente A JOIN Inserted B ON A.Name = B.Name END GO |
Ao executar um simples comando de UPDATE, veremos que a trigger foi disparada nas duas tabelas
1 2 3 |
UPDATE dbo.Funcionario SET Name = 'Dirceu Resende' WHERE Id_Funcionario = 1 |
Que legal! Mesmo o comando vindo de outra trigger, foi possível identificar a origem dessa alteração.
Mas e se você quiser mais detalhes da origem desse comando e identificar toda a cadeia de execução da trigger? Bom, neste caso, sugiro a leitura do artigo SQL Server – Como identificar e monitorar a execução de triggers.
Espero que vocês tenham gostado desse artigo e até a próxima 🙂
Abraços!