TRIGGER de atualização aninhado

Ola galera. Este é meu primeiro artigo para começo de conversa. De químico e programador louco só eu tenho um pouco!

Esta noite andei fuçando no software que estou desenvolvendo, um pequeno sistema para resultados de análises químicas e me deparei com a seguinte situação: Eu precisava facilitar a atualização e inclusão de registros em tabelas de forma mais simples. Para isso imaginei a seguinte solução de escrever na tabela A colocaria informações na Tabela tabB e tabC. Se atualizasse a tabela tabB colocaria as informações na tabela C. Pensando nisto eu resolvi brincar um pouco com TRIGGER de Inclusão, mais especificamente, após inclusão (AFTER INSERT).

A ideia é facilitar quando ao escrever apenas o código da trigger da tabela tabA para inserir registros na tabela tabB. Escrever apenas o código da trigger da tabela tabB para inserir na tabela tabC. Assim, evitará um  outro cenário que seria fazer todo o código da trigger da tabA para escrever na tabela tabB e tabC e isto ficaria mais complexo. Além de referenciar as tabelas tabB e tabC para a sua escrita. Teremos que ter todo cuidado para evitar de disparar a trigger da tabela tabB que também irá escrever na tabela tabC. Neste momento devemos desativar a trigger da tabela tabB para evitar a escrita na tabela tabC o que no final das contas estaríamos escrevendo duas vezes na tabela tabC. Desta maneira o código fica um pouco mais complexo.

Espero que tenham entendido estas logica. Vamos a prática que ficará tudo mais claro a ideia.

Primeiro vamos criar duas tabelas chamada tabA, tabB e tabC

CREATE TABLE [dbo].[tabA] (
  [Indice] [int] NOT NULL,
  [AA] [int] NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[tabB](
  [Indice] [int] NOT NULL,
  [IndiceA] [int] NOT NULL,
  [BB] [varchar](50) NULL
) ON [PRIMARY]

CREATE TABLE.[tabC](
  [CC] [varchar](50) NULL
)

Agora vamos construir as triggers de cada uma das tabelas tabA e tabB

CREATE TRIGGER [dbo].[TRG_A_AFTER_INSERT]
ON [dbo].[tabA]
AFTER INSERT
AS
BEGIN
BEGIN TRY
  — SET NOCOUNT ON added to prevent extra result sets from
  — interfering with SELECT statements.
  SET NOCOUNT ON;

  DECLARE @value_Indice INT;
  DECLARE Inserted_Cursor CURSOR LOCAL SCROLL DYNAMIC OPTIMISTIC FOR
  SELECT
    inserted.Indice
  FROM
    inserted
  
  OPEN Inserted_Cursor;
  
  FETCH FIRST FROM inserted_Cursor INTO @value_Indice;
  
  WHILE (@@fetch_status= 0)
  BEGIN
    — Adicionar estrutura em _B
    INSERT INTO tabB(Indice, IndiceA, BB)
    VALUES(
      ROUND(RAND((DATEPART(mm,GETDATE())* 100000 )
      +(DATEPART(ss,GETDATE())* 1000 )
      +DATEPART(ms,GETDATE()))*100000000, 0),
      @value_Indice,
      ”);
    
    FETCH NEXT FROM Inserted_Cursor INTO @value_Indice;
  END;
  CLOSE Inserted_Cursor;
  DEALLOCATE Inserted_Cursor;
END TRY
BEGIN CATCH
  DECLARE @ErrorMessage NVARCHAR(4000);
  DECLARE @ErrorSeverity INT;
  DECLARE @ErrorState INT;
  SELECT @ErrorMessage =ERROR_MESSAGE();
  SELECT @ErrorSeverity =ERROR_SEVERITY();
  SELECT @ErrorState =ERROR_STATE();
  RAISERROR ( @ErrorMessage, @ErrorSeverity, @ErrorState);
  PRINT‘ERROR_MESSAGE: ‘+ @ErrorMessage +
    ‘ ERROR_SEVERITY: ‘+CAST(@ErrorSeverity ASVARCHAR(12))+
    ‘ ERROR_STATE: ‘+CAST(@ErrorState ASVARCHAR(12));
  RETURN;
END CATCH
END
CREATE TRIGGER [dbo].[TRG_B_AFTER_INSERT]
ON [dbo].[tabB]
AFTER INSERT
AS
BEGIN
BEGIN TRY
  — SET NOCOUNT ON added to prevent extra result sets from
  — interfering with SELECT statements.
  SET NOCOUNT ON;
  DECLARE @value FLOAT;
  –Adicionar registros na tabela _C
  INSERTINTO tabC(CC)VALUES(CAST(ROUND(RAND((DATEPART(mm,GETDATE())* 100000 )
  +(DATEPART(ss,GETDATE())* 1000 )
  +DATEPART(ms,GETDATE()))*100000000, 0)ASVARCHAR(50)));

  –Serve para provocar o erro DIV#0
  SET @value = 1;
  SET @value = @value / 0;
END TRY
BEGIN CATCH
  DECLARE @ErrorMessage NVARCHAR(4000);
  DECLARE @ErrorSeverity INT;
  DECLARE @ErrorState INT;
  SELECT @ErrorMessage =ERROR_MESSAGE();
  SELECT @ErrorSeverity =ERROR_SEVERITY();
  SELECT @ErrorState =ERROR_STATE();
  RAISERROR ( @ErrorMessage, @ErrorSeverity, @ErrorState);
  PRINT‘ERROR_MESSAGE: ‘+ @ErrorMessage +
    ‘ ERROR_SEVERITY: ‘+CAST(@ErrorSeverity ASVARCHAR(12)) +
    ‘ ERROR_STATE: ‘+CAST(@ErrorState ASVARCHAR(12));
  RETURN;
END CATCH
END

Pronto já Possuimos as 3 estruturas de tabela com seus trigger.

Perceba que não coloquei nenhum BEGIN TRAN finalizado com COMMIT TRAN dentro da trigger por que a própria execução da trigger, na atual seção do sql server, já executa sobre uma transação principal e somente após todos os processos das trigger terminarem de executar dentro da seção é que ocorre um COMMIT TRAN. Caso ocorra uma exceção durante a execução da trigger o ROLLBACK TRAN é executado para desfazer todas as modificações realizadas nas tabelas ou banco de dados. Neste caso todas as ações de escrever, delatar e atualizar serão desfeitas como que nada tivesse acontecido.

Provocando o Erro

Eu coloquei no código da trigger TRG_B_AFTER_INSERT mostrado abaixo que exemplifica quando realiza a inclusão de registros na tabela tabA e tabB são desfeita quando ocorre uma divisão por zero.

SET @value = 1;
SET @value = @value / 0;

Removendo o trecho do código mostrado acima da trigger TRG_B_AFTER_INSERT as 3 tabelas serão atualizadas de forma aninhada (NESTED).

faça o experimento deixando e removendo o trecho do código acima na trigger.

Testando

Abaixo eu coloco uma T-SQL de teste para inclusão de registros na tabela tabA

INSERT INTO tabA(Indice, AA) VALUES (1, 100);
INSERT INTO tabA(Indice, AA) VALUES (2, 100);
INSERT INTO tabA(Indice, AA) VALUES (3, 100);
INSERT INTO tabA(Indice, AA) VALUES (4, 100);

É isto por enquanto pessoal e espero ter ajudado a quem estava com dúvidas se realmente ao escrever na tabela tabA (disparando o seu trigger) iria atualizar a tabela tabB (disparando seu trigger) iria por sua vez escrever na tabela tabC.

Sobre Guilherme Wiethaus

Formado em Química com mestrado e atualmente aluno de doutorado e profissional atuando em química analítica e instrumental. Além desta formação trabalhei em programação, desenvolvimento de sistemas nas linguagens Delphi, Visual Basic .NET, e HTML/CSS e Assembly x86. Atualmente levo como Hobbies os conhecimentos que são aplicados também aos meus trabalhos em química. Desenvolvimento em Delphi e SQL Server.
Esse post foi publicado em SQL Server. Bookmark o link permanente.

Deixe um comentário