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.