Anda di halaman 1dari 29

Oracle Database 11g: PL/SQL

TRIGGERS
Objetivos
 Descrever o uso de database triggers;
 Descrever os diferentes tipos de triggers;
 Criar database triggers;
 Descrever database trigger-firing rules;
 Remover database triggers;
 Visualizar informações de trigger.
O que são Triggers
 Bloco PL/SQL armazenado no banco de dados e executado em
resposta a um evento;
 A trigger é lançada automaticamente quando especificas
condições ocorrerem.
Criando um package padrão de
exceção
 A trigger pode ser definida em tabela, view, esquema ou database.
Tipos de Trigger Event
 Possibilita que triggers sejam disparadas sempre que uma das
seguintes ocorrências acontecerem:
 Manipulação DML (DELETE, INSERT ou UPDATE);
 Definição de banco de dados DDL (CREATE, ALTER ou
DROP)
 Operações de banco de dados SERVERERROR, LOGON,
LOGOFF, STARTUP ou SHUTDOWN.
Application e Database Triggers
 Database trigger:
 Lançada sempre que ocorrer uma DML, DDL ou evento de sistema
em qualquer esquema ou banco de dados.

 Application trigger:
 Lançada sempre que ocorrer um evento com uma aplicação
especifica.
Cenários para implementação de
Triggers
 As triggers podem ser usadas para:
 Segurança;
 Auditoria;
 Integridade de dados;
 Integridade referencial;
 Replicação de tabelas;
 Computação de derivação de dados;
 Eventos de logging.
Avaliação de tipos de Trigger
 DML Triggers:
 BEFORE;
 AFTER;
 INSTEAD OF.
 Trigger composta;
 Não-DML triggers;
 Eventos DDL;
 Eventos de banco de dados.
Tipos de eventos e corpo de
Trigger
 O tipo de evento da trigger determina qual instrução DML
chama uma trigger. Os possíveis eventos são:
 INSERT;
 UPDATE [OF COLUMN];
 DELETE.
 No corpo, desenvolvimento, da trigger é determinado as suas
ações podendo também realizar chamada a procedures.
Criando uma DML Trigger usando a
expressão CREATE TRIGGER
Especificando Firing Triggers
(Timing)
 A trigger timing ocorre sempre para executar uma ação da
trigger antes ou depois da expressão com uma timing trigger
implementada:
 BEFORE: Executa a trigger antes do evento de DML sobre a
tabela;
 AFTER: Executa a trigger depois do evento de DML sobre a
tabela;
 INSTEAD OF: Executa a trigger para views que não são
modificadas.
Trigger em nível de expressão e
linhas
Trigger no nível de expressão Trigger no nível de linha
Default quando criando uma trigger. Usada com FOR EACH ROW quando
criada uma trigger.
Disparada para cada evento de trigger. Dispara da uma vez para cada linha
afetada.
Dispara uma vez, mesmo que Caso nenhuma linha seja afetada a
nenhuma linha é afetada. trigger não é disparada.
Criando Trigger para expressão DML

CREATE OR REPLACE TRIGGER seguranca_employees


BEFORE INSERT ON employees
BEGIN
IF (TO_CHAR(SYSDATE, 'DY') IN ('SAB', 'DOM') OR
TO_CHAR(SYSDATE, 'hh24:mi') NOT BETWEEN '08:00'
AND '18:00') THEN
RAISE_APPLICATION_ERROR(-20500, 'Você não pode
manipular dados fora do horário.');
END IF;
END;
Usando condicionais em Triggers
CREATE OR REPLACE TRIGGER seguranca_employees
BEFORE INSERT OR UPDATE OR DELETE ON employees
BEGIN
IF (TO_CHAR(SYSDATE,'DY') IN ('SAB','DOM')) OR
(TO_CHAR(SYSDATE,'HH24') NOT BETWEEN '08' AND '18') THEN
IF DELETING THEN
RAISE_APPLICATION_ERROR(-20502,
'DELETE na tabela EMPLOYEES permitida somente durante
o expediente.');
ELSIF INSERTING THEN
RAISE_APPLICATION_ERROR(-20500,
'INSERT na tabela EMPLOYEES permitida somente durante
o expediente.');
ELSIF UPDATING('SALARY') THEN
RAISE_APPLICATION_ERROR(-20503,
'UPDATE Salário na tabela EMPLOYEES permitida somente
durante o expediente.');
ELSE
RAISE_APPLICATION_ERROR(-20504,
'UPDATE SALARY na tabela EMPLOYEES permitida somente
durante o expediente.');
END IF;
END IF;
END;
Usando condicionais em Triggers
(cont.)
INSERT INTO employees (employee_id,
last_name, first_name, email, hire_date,
job_id, salary, department_id)
VALUES (300, 'Smith', 'Rob', 'RSMITH',
SYSDATE,'IT_PROG', 6000, 60);
Criando Trigger para DML em linha
CREATE OR REPLACE TRIGGER
manipulando_salary
BEFORE INSERT OR UPDATE OF salary ON
employees
FOR EACH ROW
BEGIN
IF NOT (:NEW.job_id IN ('AD_PRES',
'AD_VP'))
AND :NEW.salary > 15000 THEN
RAISE_APPLICATION_ERROR (-20202, 'O
salário não pode ser maior que
R$15.000,00');
END IF;
END;
Criando Trigger para DML em linha:
Exemplo
INSERT INTO employees (employee_id,
last_name, first_name, email, hire_date,
job_id, salary, department_id)
VALUES (300, 'Smith', 'Rob', 'RSMITH',
SYSDATE,'IT_PROG', 18000, 60);
/
UPDATE employees
SET salary = 15500
WHERE last_name = 'Russell';
Usando qualificador OLD e NEW
 Para cada vez que a trigger é lançada em instrução de única linha
o PL/SQL cria duas estruturas em tempo de execeção:
 OLD: Armazena o valor original do registro que esta em
processamento;
 NEW: Contém o novo valor.

 NEW e OLD tem a mesma estrutura de registro declarada


usando o atributo %ROWTYPE sobre a tabela que a trigger que foi
definida.
Operação de dados Valor OLD Valor NEW
INSERT NULL. Novo valor inserido.
UPDATE Valor antes do update. Valor após o update.
DELETE Valor antes do delete. NULL.
Usando qualificadores OLD e NEW: Exemplo
CREATE TABLE audit_emp (
user_name VARCHAR2(30),
time_stamp date,
id NUMBER(6),
old_last_name VARCHAR2(25),
new_last_name VARCHAR2(25),
old_title VARCHAR2(10),
new_title VARCHAR2(10),
old_salary NUMBER(8,2),
new_salary NUMBER(8,2));

CREATE OR REPLACE TRIGGER auditoria_valores_employees


AFTER DELETE OR INSERT OR UPDATE ON employees
FOR EACH ROW
BEGIN
INSERT INTO audit_emp(user_name, time_stamp, id,
old_last_name, new_last_name, old_title,
new_title, old_salary, new_salary)
VALUES (USER, SYSDATE, :OLD.employee_id,
:OLD.last_name, :NEW.last_name, :OLD.job_id,
:NEW.job_id, :OLD.salary, :NEW.salary);
END;
Usando qualificadores OLD e NEW: Exemplo

INSERT INTO employees (employee_id, last_name,


job_id, salary, email, hire_date)
VALUES (999, 'Temp emp', 'SA_REP', 6000, 'TEMPEMP',
TRUNC(SYSDATE))
/
UPDATE employees
SET salary = 7000, last_name = 'Smith'
WHERE employee_id = 999;
/
SELECT *
FROM audit_emp;
Usando a cláusula WHEN para Triggers baseada
em condição
CREATE OR REPLACE TRIGGER verifica_commissao
BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
WHEN (NEW.job_id = 'SA_REP')
BEGIN
IF INSERTING THEN
:NEW.commission_pct := 0;
ELSIF :OLD.commission_pct IS NULL THEN
:NEW.commission_pct := 0;
ELSE
:NEW.commission_pct := :OLD.commission_pct+0.05;
END IF;
END;
Implementando AFTER TRIGGER para
Integridade de Constraint
UPDATE employees SET department_id = 999
WHERE employee_id = 170;

CREATE OR REPLACE TRIGGER employee_dept_fk_trg


AFTER UPDATE OF department_id
ON employees FOR EACH ROW
BEGIN
INSERT INTO departments VALUES(:new.department_id,
'Dept '||:new.department_id, NULL, NULL);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
NULL;
END;
/

UPDATE employees SET department_id = 999


WHERE employee_id = 170;
INSTEAD OF TRIGGER
Criando uma INSTEAD OF
TRIGGER: Exemplo
Criando uma INSTEAD OF TRIGGER
para DML em view
CREATE TABLE novos_empregados AS
SELECT employee_id, last_name, salary, department_id
FROM employees;

CREATE TABLE novos_departamentos AS


SELECT dep.department_id, dep.department_name,
SUM(emp.salary) salary_depto
FROM departments dep
INNER JOIN employees emp ON (dep.department_id
= emp.department_id)
GROUP BY dep.department_id, dep.department_name;

CREATE VIEW detalhes_empregados AS


SELECT emp.employee_id, emp.last_name, emp.salary,
emp.department_id, dep.department_name
FROM departments dep
INNER JOIN employees emp ON (dep.department_id
= emp.department_id);
CREATE OR REPLACE TRIGGER novos_emp_depto
INSTEAD OF INSERT OR UPDATE OR DELETE ON detalhes_empregados
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO novos_empregados
VALUES (:NEW.employee_id, :NEW.last_name, :NEW.salary, :NEW.department_id);
UPDATE novos_departamentos
SET salary_depto = salary_depto + :NEW.salary
WHERE department_id = :NEW.department_id;
ELSIF DELETING THEN
DELETE FROM novos_empregados
WHERE employee_id = :OLD.employee_id;
UPDATE novos_departamentos
SET salary_depto = salary_depto - :OLD.salary
WHERE department_id = :OLD.department_id;
ELSIF UPDATING ('salary') THEN
UPDATE novos_empregados
SET salary = :NEW.salary
WHERE employee_id = :OLD.employee_id;
UPDATE novos_departamentos
SET salary_depto = salary_depto +
(:NEW.salary - :OLD.salary)
WHERE department_id = :OLD.department_id;
ELSIF UPDATING ('department_id') THEN
UPDATE novos_empregados
SET department_id = :NEW.department_id
WHERE employee_id = :OLD.employee_id;
UPDATE novos_departamentos
SET salary_depto = salary_depto - :OLD.salary
WHERE department_id = :OLD.department_id;
UPDATE novos_departamentos
SET salary_depto = salary_depto + :NEW.salary
WHERE department_id = :NEW.department_id;
END IF;
END;
Status da TRIGGER
 A Trigger possui dois tipos de status:
 Habilitada (enabled): A Trigger é executada caso a sua ação
seja solicitada.
 Desabilitada (disabled): Nenhuma ação será executada quando
uma trigger estiver definida como desabilitada.
Gerenciando TRIGGER usando
instruções ALTER e DROP
 Habilitar e desabilitar Trigger:
ALTER TRIGGER novos_emp_depto DISABLE;
ALTER TRIGGER novos_emp_depto ENABLE;
 Habilitar e desabilitar Trigger de tabela:
ALTER TABLE employees DISABLE ALL TRIGGERS;
ALTER TABLE employees ENABLE ALL TRIGGERS;

 Recompilar Trigger:
ALTER TRIGGER novos_emp_depto COMPILE;
 Excluir Trigger:
DROP TRIGGER novos_emp_depto;
Visualizando função a partir do
dicionário de dados
 USER_OBJECTS: Informações do objeto, como data de criação e status.
SELECT *
FROM user_objects
WHERE object_type LIKE 'TRIGGER'
AND object_name LIKE UPPER('novos_emp_depto');

 DBA_TRIGGERS: Informações detalhadas da Trigger.


SELECT *
FROM dba_triggers
WHERE trigger_name LIKE UPPER('novos_emp_depto');

 USER_ERRORS: Erro existentes na Trigger, quando houver.


SELECT *
FROM user_errors
WHERE object_type LIKE 'TRIGGER'
AND name LIKE UPPER('novos_emp_depto');

Anda mungkin juga menyukai