Boa Noite queridos compatriotas!!! Mais uma vez aqui unidos, juntos, misturados para mais uma aventura pelo mundo do SQL. Para vocês trago a famosa Trigger. Com alguns exemplos postos em questão fica muito mais fácil de compreender. As Triggers são conhecidas como Gatilhos. Esse nome é definido assim pois é disparado um comando a partir do momento em que foi usado um insert, um delete ou mesmo um update. Como isso?? Um exemplo simples, apenas a título de conhecimento, imaginemos que por um acaso, em uma bela manhã ensolarada, acordei e resolvi fazer um insert. Ótimo, mas ao mesmo tempo que tomar alguns dados e inserílos em outra entidade (tabela), porém não quero todo o insert e sim alguns dados apenas e com algumas condições.   Ah eu até poderia fazer vários Inserts em todas as entidades... Mas o problema é "e se de repente eu resolva fazer um novo insert e outro e mais outro, inúmeros inserts e que todos tenham exijam um parâmetro, um parâmetro responsável por enviar ou não tais dados a outras tantas entidades?", para isso precisamos de algo que faça esse serviço. Vamos começar então.
Criando o ambiente 
Ótimo já chegamos até aqui. Se você teve paciência e foi vitorioso(a), vamos preparar o ambiente. Todos estão com o SQL Server aí?? Quem não pode buscá-lo vamos precisar. 
Conecte-se e crie um banco:
CREATE DATABASE bd_Trigger
USE bd_Trigger
O próximo passo é criar as entidades. Por elas criaremos toda a ordem de negócio, simples por sinal. A propósito vou dedicar um post com uma conversa sobre modelagem, muito útil.
Bom voltando iremos criar quatro entidades: Produto, LogPreco, PedidoCompra, ProdutosExcluidos.
Veja:
CREATE TABLE ProdutosExcluidos(
 cd_Produto INT NULL,
 ds_produto VARCHAR(50) NULL,
 dt_exclusao SMALLDATETIME NULL)
 
CREATE TABLE Produto(
 cd_Produto INT NOT NULL,
 ds_Produto VARCHAR(50) NOT NULL,
 vl_Produto MONEY NULL,
 qt_Estoque INT NULL,
 qt_Estoquemin INT NULL,
 CONSTRAINT PK_Produto PRIMARY KEY CLUSTERED(cd_Produto))
 CREATE TABLE PedidoCompra(
 cd_PedidoCompra INT IDENTITY NOT NULL,
 cd_Produto INT NOT NULL,
 dt_Solicitacao SMALLDATETIME  NOT NULL, 
 qt_Compra INT NOT NULL,
 CONSTRAINT PK_PedidoCompra PRIMARY KEY CLUSTERED (cd_PedidoCompra))
 CREATE TABLE LogPreco(
 cd_LogPreco INT IDENTITY NOT NULL,
 dt_Alteracao SMALLDATETIME NOT NULL,
 cd_Produto INT NOT NULL,
 vl_ProdutoAntigo MONEY NOT NULL,
 vl_ProdutoNovo MONEY NOT NULL,
 CONSTRAINT PK_LogPreco PRIMARY KEY CLUSTERED (cd_LogPreco))
Ótimo. Agora vamos fazer alguns relacionamentos. Não havia feito antes porque acho muito mais interessante fazê-lo já tendo as tabelas construídas. É uma forma de visualizar o que possuo antes de sair disparando relacionamentos. Veja:
ALTER TABLE LogPreco
ADD CONSTRAINT fk_LogPreco
FOREIGN KEY (cd_Produto)
REFERENCES Produto (cd_Produto)
ALTER TABLE PedidoCompra
ADD CONSTRAINT fk_PedidoCompra
FOREIGN KEY (cd_Produto)
REFERENCES Produto (cd_Produto)
Após tudo estar preparado vamos para a parte que todos esperavam.. a Trigger.
Vamos começar com uma trigger que deverá ser disparada nas operações de UPDATE, o que significa que quando fizermos um update ela automaticamente irá disparar valores. Como assim? Vamos supor que eu queira alterar o valor de alguns preço na tabela de Produto e ainda assim queira manter um registro dos valores antigos. Ao invés de fazer a alteração e depois inserir manualmente o que seria uma perca de tempo e poderia até gerar a inconsistência do dado ou mesmo a não inserção do valor alterado na tabela  de histórico, a trigger automaticamente faria esse trabalho sujo (sahuasu). Então a ideia é fazer um trigger ligando a tabela Produto e LogPreco. Vamos deixar claro que cd_logpreco é autonumeração, ou seja não requer digitação, aliás nem é possível tal coisa, isso significa que não deve constar na lista de campos quando a trigger for executar o insert na tabela Log.
Primeiro vamos inserir alguns valores:
INSERT Produto([cd_Produto], [ds_Produto] ,  [vl_Produto] , [qt_Estoque] , [qt_Estoquemin]) VALUES  ( 1 , 'Prego' , 1.0000 , 25 , 10) 
INSERT Produto ( [cd_Produto] , [ds_Produto] , [vl_Produto] , [qt_Estoque] , [qt_Estoquemin] )  VALUES  ( 2 , 'Martelo' , 50.0000, 30 , 15) 
INSERT Produto ( [cd_Produto] , [ds_Produto] , [vl_Produto] , [qt_Estoque] , [qt_Estoquemin] )  VALUES  ( 3 , 'Parafuso' , 2.0000 ,  10 ,  5) 
INSERT Produto ( [cd_Produto] , [ds_Produto] , [vl_Produto] , [qt_Estoque] , [qt_Estoquemin] )   VALUES  ( 4 , 'Chave de Fenda' , 25.0000 , 15 , 10)
Agora faça os testes a seguir:
SELECT * FROM LogPreco
SELECT * FROM Produto
Este é o resultado que deve ser visualizado:
Você vai poder colar tudo se precisar na query, já que os comentários estão..comentados! 
--Agora vamos criar a Trigger:
CREATE TRIGGER tr_MudancaValor ON Produto FOR UPDATE
--Vamos comentar essa primeira linha. Aqui a ideia é fazer um gatilho que
--dispare em um Update, certo? Então repare que utilizamos "FOR UPDATE" ou seja para um update, em uma tradução grosseira.
--Nesse momento vamos criar variáveis. A função de cada variável vai variar, literalmente da 
--variação da nossa necessidade com relação toda a regra de negócio. Repare a 
--indispensabilidade em informar o tipo da variável. São iguais as dos campos que vão atribuir 
--os valores. Verá logo o porque.
AS
 DECLARE @dt_alteracao SMALLDATETIME
 DECLARE @cd_produto INT
 DECLARE @vl_produtoant MONEY
 DECLARE @vl_produtonovo MONEY
 
--Algo que talvez você não conheça, mas será apresentado nesse momento. Pois bem, cada vez 
--que você faz um Update, duas tabelas temporárias, de uso do banco, mas que nós muitos  
que  --elas fazem, ou melhor dizendo armazenam (temporariamente, importante frizar) é os novo
--espertos iremos usufruir desse bem, ssão criadas. Elas se chamam Inserted e Deleted. O
s  --valores e os antigos, nesta oredem. Nesse caso o que você tinha gravado, temporáriamente está nca, jamais, never, ouviu, never, diga que além dessas duas tabelas existe  --uma cham
--na tabele Deleted e o que você resolveu alterar está em Inserted. Pesso agora muita  --atenção, n
uada Update, está me lendo?? Continuando...
--Repare que as variáveis @cd_produto e @vl_produtoant recebem os valores de cd_Produto 
--e vl_Produto, nesta ordem, de Deleted. O que significa que nesse momento estou usando 
--do poderoso recurso de coletar dos antigos registros (momentaneos) da tabela Deleted.
 
 SELECT @cd_produto=cd_Produto,@vl_produtoant=vl_Produto FROM DELETED
 
 --Faço o mesmo com a tabela Inserted para a variável @vl_produtoant. A diferença é 
--para @dt_alteracao que utilizo a função GETDATE(), para recuperar a data da "alteração".
 
 SELECT @dt_alteracao = GETDATE() , @vl_produtoant  = vl_Produto FROM INSERTED
 
--No final inserimos todos os valores dessas vaiáveis nos campos da tabela LogPreco e temos 
--uma inserção automática e com valores que custariam muito tempo para buscálos, analisá-los 
--e inserí-los manualmente.
 
 INSERT INTO LogPreco VALUES 
(@dt_alteracao,@cd_produto , @vl_produtoant , @vl_produtoant)
Vamos fazer um teste antes de executar a Trigger:
SELECT * FROM LogPreco
Esse deve ser o resultado:
Facinante, não? Também achei. Bom agora o momento que todos esperavam... Vamos testar a Trigger!
UPDATE Produto SET vl_Produto*=1.50
"Mas... você disse que íamos testar a Trigger e não fazer um Update!"
Sim, e nós testamos! Claro que muitos "mas..." devem estar surgindo em sua cabeça, mas é assim mesmo. Lembra que a ideia de um gatilho é justamente essa (deste ao menos) "Ao fazer um Update, que certos dados sejam armazenados automaticamente na tabela LogPreco", então foi o que fizemos, o resultado é esse:
Repare que 1 e 4 linhas foram afetadas, 4 alterações e 1 que você entenderá porque após esse teste:
SELECT * FROM LogPreco
Resultado:
Faça outros testes de Update... e veja os resultados! Agora deixo vocês e aguardem o próximo post: "Trigger para Delete". Até mais ^^ o/