Módulo 2 · SQL Server / Procedures — Capítulo 11

Triggers e Procedures

Código que roda sozinho quando uma tabela muda — o que são triggers, como se relacionam com procedures, e por que devem ser usadas com moderação.

1. O que é uma trigger

Uma trigger é um bloco de T-SQL, parecido com uma procedure, mas que não é chamado explicitamente com EXEC — ele dispara automaticamente quando um INSERT, UPDATE ou DELETE acontece numa tabela.

Stored ProcedureTrigger
Como é iniciadaChamada explícita: EXEC nomeAutomática, ao INSERT/UPDATE/DELETE na tabela
Quem decide quando rodarQuem chama (aplicação, outra procedure)O próprio SQL Server, sempre
Visibilidade no códigoExplícita — aparece no código C# ou script que chamaImplícita — só olhando a tabela no SSMS você descobre que existe
Por que usar com moderação

Uma trigger é lógica invisível do ponto de vista de quem escreve um INSERT simples anos depois, sem saber que aquilo dispara uma cascata de efeitos colaterais. É uma fonte comum de bugs difíceis de rastrear em sistemas legados. Use triggers para auditoria e integridade — não para regra de negócio que poderia estar numa procedure, onde fica visível.

2. AFTER vs. INSTEAD OF

TipoQuando rodaUso típico
AFTER (ou FOR)Depois que o comando já foi aplicado à tabelaAuditoria, sincronizar outra tabela, validação pós-fato com ROLLBACK
INSTEAD OFNo lugar do comando original — você decide o que de fato aconteceViews que precisam aceitar INSERT/UPDATE, regras complexas de substituição

3. As tabelas mágicas: inserted e deleted

Dentro de qualquer trigger, duas tabelas temporárias ficam disponíveis automaticamente: inserted (linhas novas/alteradas) e deleted (linhas antigas/removidas). Um UPDATE popula as duas ao mesmo tempo — deleted tem o valor antigo, inserted tem o novo.

SQL trigger de auditoria (AFTER UPDATE)
CREATE TABLE dbo.ClienteAuditoria
(
    Id            INT IDENTITY(1,1) PRIMARY KEY,
    ClienteId     INT NOT NULL,
    EmailAntigo   NVARCHAR(150),
    EmailNovo     NVARCHAR(150),
    AlteradoEm    DATETIME2 NOT NULL DEFAULT SYSDATETIME()
);
GO

CREATE TRIGGER trg_Cliente_AuditarEmail
ON dbo.Cliente
AFTER UPDATE
AS
BEGIN
    SET NOCOUNT ON;

    IF NOT UPDATE(Email)
        RETURN; -- só audita se a coluna Email realmente mudou

    INSERT INTO dbo.ClienteAuditoria (ClienteId, EmailAntigo, EmailNovo)
    SELECT d.Id, d.Email, i.Email
    FROM deleted d
    INNER JOIN inserted i ON i.Id = d.Id
    WHERE d.Email <> i.Email;
END;
GO
Nota

UPDATE(Email) dentro de uma trigger não é o comando UPDATE — é uma função que responde se aquela coluna específica foi mencionada no comando que disparou a trigger. Um recurso pouco conhecido, mas útil para evitar processamento desnecessário.

Cuidado com múltiplas linhas

Uma trigger dispara uma única vez por comando, não uma vez por linha — se um UPDATE afeta 500 linhas, inserted e deleted têm 500 linhas cada, todas de uma vez. Escrever a trigger assumindo "uma linha só" (um erro comum de quem vem de outros bancos) quebra silenciosamente em operações em lote.

4. Chamando uma procedure de dentro de uma trigger

É possível, e às vezes útil para reaproveitar lógica já escrita:

SQL trigger delegando para uma procedure
CREATE TRIGGER trg_Cliente_AposInserir
ON dbo.Cliente
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @Id INT = (SELECT TOP 1 Id FROM inserted);

    EXEC dbo.usp_NotificarNovoCliente @ClienteId = @Id;
END;
GO
Atenção

O exemplo acima assume uma única linha inserida por vez (TOP 1). Se o INSERT de origem afetar múltiplas linhas, essa trigger processaria só a primeira — um bug real e comum. Para múltiplas linhas, prefira um cursor sobre inserted ou, melhor ainda, redesenhar a procedure chamada para aceitar um Table-Valued Parameter (capítulo 8) com todos os Ids de uma vez.

5. Onde isso te leva

Triggers fecham o conjunto de ferramentas de escrita do T-SQL. A partir do próximo capítulo, o foco muda de "como escrever" para "como organizar" — nomenclatura, estrutura de projeto e como tudo isso se conecta de volta à sua aplicação C#.

📌 Resumo do capítulo

  • Trigger dispara automaticamente em INSERT/UPDATE/DELETE — diferente de procedure, que precisa ser chamada explicitamente.
  • AFTER roda depois do comando aplicado; INSTEAD OF substitui o comando original.
  • As tabelas inserted e deleted sempre podem conter múltiplas linhas — nunca assuma uma linha só.
  • Use triggers para auditoria/integridade; evite colocar regra de negócio "escondida" nelas.

✏️ Praticando

  1. Crie a tabela ClienteAuditoria e a trigger trg_Cliente_AuditarEmail.
  2. Rode um UPDATE que altera o e-mail de 3 clientes de uma vez só (um único comando) e confirme que as 3 linhas de auditoria foram geradas.
  3. Reescreva a trigger da seção 4 para funcionar corretamente quando múltiplas linhas são inseridas de uma vez.