BD II (SI 587) Gatilhos (Triggers) Prof. Josenildo Silva jcsilva@ifma.edu.br
Motivação Algumas rotinas precisam ser executadas antes ou depois de um determinado evento no banco de dados
Motivação Regras de negócios complexas precisam ser verificadas a cada operação do banco de dados
Motivação Somente com visões, funções e procedimentos não é possível realizar nenhuma das duas situações
TRIGGERS
O que são triggers? É um conjunto de operações executadas automaticamente quando uma alteração é feita em uma tabela
Execução É disparada (pelo SGBD) antes ou depois de um INSERT, UPDATE ou DELETE Pode haver até seis triggers por tabela
Utilização de Triggers Atender regras de negócios Verificar a integridade dos dados, pois é possível fazer uma verificação antes da inserção do registro Contornar erros na regra de negócio do sistema no banco de dados; Auditar as mudanças nas tabelas.
Exemplos Aprovar financiamento maiores que um determinado valor Atualizar uma tabela de auditoria após alteração de um registro em outra tabela. 9
Triggers em SQL Comando CREATE TRIGGER Um trigger típico tem três componentes: Evento(s) Condição Ação
Triggers em SQL Comando CREATE TRIGGER Um trigger típico tem três componentes: Evento(s) Condição Ação
Triggers em SQL Comando CREATE TRIGGER Um trigger típico tem três componentes: Evento(s) Condição Ação
Acesso a outras tabelas Uma TRIGGER é sempre associada a uma tabela, porém os seus comandos podem acessar dados de outras tabelas 13
Exemplo de acesso a outras tabelas Dadas as tabelas Nota_Fiscal(Num_nota, valor_total) Produto(Cod_Prod, nome, preço, estoque) Nota_Prod(Num_nota, Cod_Prod, quantidade) Pode-se criar uma trigger para a operação de INSERT na tabela Nota_Prod que atualiza o nível de estoque do produto vendido *
Eventos em cascata Pode-se usar TRIGGERS para exclusão e atualização em cascata Se um comando executado violar uma CONSTRAINT, a TRIGGER não irá disparar. *
Restrições Não são permitidos os seguintes comandos: ALTER DATABASE, CREATE DATABASE, DROP DATABASE, LOAD DATABASE, LOAD LOG, RESTORE DATABASE, RESTORE LOG, RECONFIGURE
Palavras chave OLD e NEW As triggers tem acesso a duas tabelas em memória referenciadas pelas palavra chave OLD e NEW
Palavras chave OLD e NEW :OLD e :NEW (No mysql se omite os dois pontos) Quando a operação for de insert temos acesso apenas a tabela :new Quando a operação for de update temos acesso as tabela :old, :new Quando a operação for de delete temos acesso apenas a tabela :old
TRIGGERS NO MYSQL
Triggers no MySQL Será criado uma trigger para cada evento das tabelas ENTRADA_PRODUTO e SAIDA_PRODUTO Nota: o MySQL não suporta múltiplos eventos em uma mesma trigger
Triggers no MySQL Padrão de nomeclatura trg + nome da tabela + id do evento AI : After Insert (Após Inserção) AU: After Update (Após Atualização) AD: After Delete (Após Exclusão)
Triggers no MySQL Serão criadas as seguintes triggers: trg_entradaproduto_ai; trg_entradaproduto_au; trg_entradaproduto_ad; trg_saidaproduto_ai; trg_saidaproduto_au; trg_saidaproduto_ad.
Triggers no MySQL TRIGGER trg_entradaproduto_ai DELIMITER $$ CREATE TRIGGER trg_entradaproduto_ai AFTER INSERT ON entrada_produto FOR EACH ROW BEGIN CALL sp_atualizaestoque (new.id_produto, new.qtde, new.valor_unitario); END $$ DELIMITER ;
Triggers no MySQL TRIGGER trg_entradaproduto_au DELIMITER $$ CREATE TRIGGER trg_entradaproduto_au AFTER UPDATE ON entrada_produto FOR EACH ROW BEGIN CALL sp_atualizaestoque (new.id_produto, new.qtde - old.qtde, new.valor_unitario ); END $$ DELIMITER;
Triggers no MySQL TRIGGER trg_entradaproduto_ad DELIMITER $$ CREATE TRIGGER trg_entradaproduto_au AFTER DELETE ON entrada_produto FOR EACH ROW BEGIN CALL sp_atualizaestoque (old.id_produto, old.qtd * -1, old.valor_unitario ); END $$ DELIMITER;
Triggers no MySQL TRIGGER trg_saidaproduto_ai DELIMITER $$ CREATE TRIGGER trg_saidaproduto_ai AFTER INSERT ON saida_produto FOR EACH ROW BEGIN CALL sp_atualizaestoque (new.id_produto, new.qtde * -1, new.valor_unitário); END $$ DELIMITER;
Triggers no MySQL TRIGGER trg_saidaproduto_au DELIMITER $$ CREATE TRIGGER trg_saidaproduto_au AFTER UPDATE ON saida_produto FOR EACH ROW BEGIN CALL sp_atualizaestoque (new.id_produto, old.qtde - new.qtde, new.valor_unitario); END $$ DELIMITER;
Triggers no MySQL TRIGGER trg_saidaproduto_ad DELIMITER $$ CREATE TRIGGER trg_saidaproduto_ad AFTER DELETE ON saida_produto FOR EACH ROW BEGIN CALL sp_atualizaestoque (old.id_produto, old.qtde, old.valor_unitário); END $$ DELIMITER;
Habilitando e Desabilitando Trigger Para desabilitar temporariamente uma trigger: ALTER TABLE Nome_da_Tabela DISABLE TRIGGER Nome_da_Trigger Para habilitar novamente uma trigger: ALTER TABLE Nome_da_Tabela ENABLE TRIGGER Nome_da_Trigger 29
TRIGGERS NO ORACLE
Triggers no Oracle Trigger são blocos PL/SQL associados com tabelas, views, esquemas
Triggers no Oracle Triggers de DML (INSERT, UPDATE e DELETE) Também: triggers INSTEAD OF para visões Triggers de DDL (CREATE, ALTER e DROP) Triggers de sistema
Triggers de DML - Sintaxe CREATE [OR REPLACE] TRIGGER <nome> {timing} event1 event2... ON {tabela} [FOR EACH ROW WHEN (predicado)] {corpo_trigger}
Exemplo 1: Trigger before-statement CREATE OR REPLACE TRIGGER BEF_STA BEFORE INSERT ON TB_AUX BEGIN DBMS_OUTPUT.PUT_LINE('Inside a BEFORE STMT TRIGGER!'); -- USE THE FOLLOWING LINE TO CANCEL THE ACTION -- RAISE_APPLICATION_ERROR(-20200,'TEST'); END; -- TESTING INSERT INTO TB_AUX VALUES(1,'A') INSERT INTO TB_AUX VALUES(2,'B') INSERT INTO TB_AUX VALUES(3,'C') SELECT * FROM TB_AUX;
Exemplo 2: Trigger before-row CREATE OR REPLACE TRIGGER BEF_ROW BEFORE UPDATE OF NAME ON TB_AUX FOR EACH ROW BEGIN DBMS_OUTPUT.PUT_LINE('Inside a BEFORE ROW TRIGGER!'); END; -- TESTING UPDATE TB_AUX SET NAME = '' WHERE ID = 100; UPDATE TB_AUX SET ID = 0; UPDATE TB_AUX SET NAME = ''; SELECT * FROM TB_AUX;
Predicados, e tabelas :old e :new Predicados indicam o tipo do trigger DELETING, INSERTING e UPDATING Tabelas :old e :new Em memória, com dados relacionados à instrução que disparou o trigger
Exemplo 3: Trigger com predicados CREATE OR REPLACE TRIGGER AFT_STA AFTER INSERT OR UPDATE OR DELETE ON TB_AUX BEGIN IF DELETING THEN RAISE_APPLICATION_ERROR(-20200,'DELETE CANCELED!'); ELSEIF INSERTING THEN RAISE_APPLICATION_ERROR(-20200,'INSERT CANCELED!'); ELSEIF UPDATING('NAME') THEN RAISE_APPLICATION_ERROR(-20200,'UPDATE CANCELED!'); END IF; END; -- TESTING SELECT * FROM TB_AUX; DELETE TB_AUX WHERE ID = 0 -- TESTING INSERT INTO TB_AUX VALUES(4,'D') UPDATE TB_AUX SET NAME = 'Z'
Exemplo 4: Trigger com :new e :old CREATE OR REPLACE TRIGGER AFT_ROW AFTER INSERT OR UPDATE OR DELETE ON TB_AUX FOR EACH ROW BEGIN IF DELETING THEN DBMS_OUTPUT.PUT_LINE('OLD ID:' TO_CHAR(:OLD.ID) ); DBMS_OUTPUT.PUT_LINE('OLD NAME:' TO_CHAR(:OLD.NAME) ); ELSIF INSERTING THEN DBMS_OUTPUT.PUT_LINE('NEW ID:' TO_CHAR(:NEW.ID)); DBMS_OUTPUT.PUT_LINE('NEW NAME:' TO_CHAR(:NEW.NAME)); ELSIF UPDATING('NAME') THEN DBMS_OUTPUT.PUT_LINE('NEW ID:' TO_CHAR(:NEW.ID) ); DBMS_OUTPUT.PUT_LINE('OLD ID:' TO_CHAR(:OLD.ID) ); DBMS_OUTPUT.PUT_LINE('NEW NAME:' TO_CHAR(:NEW.NAME) ); DBMS_OUTPUT.PUT_LINE('OLD NAME:' TO_CHAR(:OLD.NAME) ); END IF; END;
Exemplo 4: cont. -- TESTING SELECT * FROM TB_AUX; DELETE TB_AUX WHERE ID = 0 INSERT INTO TB_AUX VALUES(4,'D') UPDATE TB_AUX SET NAME = 'Z'
Exemplo 5: cláusula WHEN CREATE OR REPLACE TRIGGER AFT_WHEN AFTER INSERT ON TB_AUX FOR EACH ROW WHEN (NEW.ID = 10) BEGIN DBMS_OUTPUT.PUT_LINE('Novo ID igual a 10'); END; -- TESTE SELECT * FROM TB_AUX; INSERT INTO TB_AUX VALUES(9,'M'); INSERT INTO TB_AUX VALUES(10,'N'); INSERT INTO TB_AUX VALUES(11,'O'); DROP TRIGGER AFT_WHEN;
Exemplo 6: cláusula WHEN CREATE OR REPLACE TRIGGER Print_salary_changes BEFORE DELETE OR INSERT OR UPDATE ON emp FOR EACH ROW WHEN (NEW.EMPNO > 0) DECLARE sal_diff number; BEGIN sal_diff := :NEW.SAL - :OLD.SAL; dbms_output.put('old salary: ' :OLD.sal); dbms_output.put('new salary: ' :NEW.sal); dbms_output.put_line('diff: ' sal_diff ); END;
Trigger instead of para Visões CREATE VIEW VW_AUX AS SELECT * FROM TB_AUX; CREATE OR REPLACE TRIGGER TR_IO INSTEAD OF INSERT ON VW_AUX FOR EACH ROW BEGIN INSERT INTO TB_AUX VALUES(:NEW.ID, :NEW.NAME); END; -- TESTES SELECT * FROM VW_AUX; SELECT * FROM TB_AUX; INSERT INTO VW_AUX VALUES(99,'W');
SEQUÊNCIA DE DISPARO para triggers no Oracle BEFORE STATEMENT BEFORE ROW AFTER ROW CONSTRAINTS CHECK AFTER STATEMENT