Você está na página 1de 57

Objetivos

3
Fundamentos das Exceções com PL/SQL

• Uma exceção é um erro PL/SQL gerado


durante a execução de um programa.
• Uma exceção pode ser gerada:
– Implicitamente pelo Oracle Server
– Explicitamente pelo programa
• Uma exceção pode ser tratada:
– Ao ser interceptada por um handler
– Ao ser propagada para o ambiente de
chamada

4
O Que É uma Exceção?

5
Tratando a Exceção: Exemplo

6
Tratando Exceções

A
exceção
foi inter- Encerre
ceptada? Não abruptamente.

Sim

A exceção Execute instruções Propague a


foi gerada. na seção EXCEPTION exceção.
.

Encerre
normalmente.

7
Tipos de Exceções

• Predefinidas no Oracle Server


• }
Não Predefinidas no Oracle Server Geradas
implicitamente

• Definidas pelo usuário Geradas explicitamente

8
Sintaxe para Interceptar Exceções

EXCEPTION
WHEN exception1 [OR exception2 . . .] THEN
statement1;
statement2;
. . .
[WHEN exception3 [OR exception4 . . .] THEN
statement1;
statement2;
. . .]
[WHEN OTHERS THEN
statement1;
statement2;
. . .]

9
Diretrizes para Interceptar Exceções

• A palavra-chave EXCEPTION inicia a seção de tratamento


de exceções.
• São permitidos vários handlers de exceções.
• Apenas um handler será processado antes de deixar o
bloco.
• WHEN OTHERS é a última cláusula.

10
Interceptando Erros Predefinidos do Servidor Oracle

• Faça referência ao nome predefinido na rotina de


tratamento de exceções.
• Exemplos de exceções predefinidas:
– NO_DATA_FOUND
– TOO_MANY_ROWS
– INVALID_CURSOR
– ZERO_DIVIDE
– DUP_VAL_ON_INDEX

11
Interceptando Erros Não
Predefinidos do Servidor Oracle

Fazer
Declarar Associar
Referência

Seção declarativa Seção EXCEPTION

Nomeie a Use PRAGMA Trate a exceção


exceção. EXCEPTION_INIT. gerada.

12
Funções para Interceptar Exceções

• SQLCODE: Retorna o valor numérico para o código de erro


• SQLERRM: Retorna a mensagem associada ao número de
erro

13
Interceptando Exceções Definidas pelo Usuário

Declarar Gerar Fazer Referência

Seção Seção Seção de


declarativa executável tratamento de exceções

Nomeie a Gere a exceção Trate a exceção


exceção. explicitamente gerada.
usando a
instrução RAISE.

14
Procedure RAISE_APPLICATION_ERROR

Sintaxe:
raise_application_error (error_number,
message[, {TRUE | FALSE}]);

• Você pode usar esse procedure para gerar mensagens de


erro definidas pelo usuário em subprogramas
armazenados.
• É possível reportar erros à aplicação e evitar o retorno de
exceções não resolvidas.

15
Procedure RAISE_APPLICATION_ERROR

• É usado em dois locais diferentes:


– Seção executável
– Seção de exceções
• Retorna condições de erro ao usuário, de modo
consistente com outros erros do Oracle Server

16
Visão Geral de Funções Armazenadas

Uma função:
• É um bloco PL/SQL nomeado que
retorna um valor
• Pode ser armazenada no banco de
dados como um objeto de esquema para
execuções repetidas
• É chamada como parte de uma
expressão ou usada para fornecer um
valor de parâmetro para outro
subprograma
• Pode ser agrupada em pacotes PL/SQL

17
Criando Funções

O bloco PL/SQL deve ter, no mínimo, uma instrução RETURN.

CREATE [OR REPLACE] FUNCTION function_name


[(parameter1 [mode1] datatype1, . . .)]
RETURN datatype IS|AS
[local_variable_declarations;
. . .]
BEGIN Bloco PL/SQL
-- actions;
RETURN expression;
END [function_name];

18
A Diferença entre
Procedures e Funções

Procedures Funções

São executados como uma instrução São chamadas como parte de uma
PL/SQL expressão

Não contêm a cláusula RETURN no Devem conter uma cláusula RETURNno


cabeçalho cabeçalho

Podem retornar valores (se houver) Devem retornar um único valor


em parâmetros de saída

Podem conter uma instrução RETURN Devem conter pelo menos uma instrução
sem um valor RETURN

19
Criando e Executando Funções: Visão Geral

Exibir erros ou advertências


no SQL Developer

SIM
Usar o comando
SHOW ERRORS
no SQL*Plus
Criar ou Advertências ou erros Exibir
editar função do compilador? advertências
ou erros
NÃO do compilador

Usar as views
USER/ALL/DBA_ERRORS

Chamar função 20
Criando e Chamando uma Função Armazenada
Usando a Instrução CREATE FUNCTION: Exemplo
CREATE OR REPLACE FUNCTION pega_sal
(p_id empregadon.cd_empregado%TYPE) RETURN NUMBER IS
v_sal empregadon.vl_salario%TYPE := 0;
BEGIN
SELECT vl_salario
INTO v_sal
FROM empregadon
WHERE cd_empregado = p_id;
RETURN v_sal;
END pega_sal;
/

EXECUTE dbms_output.put_line(pega_sal(100))

21
Usando Diferentes Métodos para Executar Funções

VARIABLE b_vl_salario NUMBER


EXECUTE :b_vl_salario := pega_sal(100)

SET SERVEROUTPUT ON
DECLARE
sal empregadon.vl_salario%type;
BEGIN
sal := pega_sal(100);
DBMS_OUTPUT.PUT_LINE('O salário é: '|| sal);
END;
/

22
Usando Diferentes Métodos para Executar Funções

EXECUTE dbms_output.put_line(pega_sal(100))

SELECT cd_empregado, pega_sal(cd_empregado)


FROM empregadon;

23
Vantagens das Funções Definidas pelo Usuário
em Instruções SQL
• Ampliam o alcance da linguagem SQL quando as
atividades são muito complexas ou não estão disponíveis
em SQL
• Aumentam a eficiência quando usadas na cláusula WHERE
para filtrar os dados, em vez de filtrá-los na aplicação
• Manipulam valores de dados

24
Usando uma Função em uma Expressão SQL:
Exemplo
CREATE OR REPLACE FUNCTION taxa(p_value IN NUMBER)
RETURN NUMBER IS
BEGIN
RETURN (p_value * 0.08);
END taxa;
/

SELECT cd_empregado, nm_empregado,


vl_salario, taxa(vl_salario)
FROM empregadon
WHERE cd_depart =10;

25
Chamando Funções Definidas pelo Usuário
em Instruções SQL
As funções definidas pelo usuário atuam como funções
incorporadas de apenas uma linha e podem ser usadas nos
seguintes locais:
• Na lista ou na cláusula SELECT de uma consulta
• Em expressões condicionais das cláusulas WHERE
e HAVING
• Nas cláusulas CONNECT BY, START WITH, ORDER BY,
e GROUP BY de uma cláusula
• Na cláusula VALUES da instrução INSERT
• Na cláusula SET da instrução UPDATE

26
Restrições à Chamada de Funções
em Expressões SQL
• As funções definidas pelo usuário que podem ser
chamadas em expressões SQL devem:
– Ser armazenadas no banco de dados
– Aceitar apenas parâmetros IN com tipos de dados SQL
válidos, e não tipos específicos PL/SQL-
– Retornar tipos de dados SQL válidos, e não tipos específicos
PL/SQL
• Ao chamar funções em instruções SQL:
– Você deve ser o proprietário da função ou ter o privilégio
EXECUTE.
– Você pode precisar ativar a palavra-chave
PARALLEL_ENABLE para permitir uma execução paralela da
instrução SQL

27
Controlando os Efeitos Colaterais ao
Chamar Funções em Expressões SQL
As funções chamadas em:
• Uma instrução SELECT não podem conter instruções DML
• Uma instrução UPDATE ou DELETE em uma tabela T não
podem consultar nem conter instruções DML na mesma
tabela T
• As instruções SQL não podem encerrar transações (ou
seja, não podem executar operações COMMIT ou
ROLLBACK)
Observação: As chamadas a subprogramas que não respeitam
essas restrições também não são permitidas na função.

28
Restrições à Chamada de Funções
em SQL: Exemplo
CREATE OR REPLACE FUNCTION dml_call_sql(p_sal NUMBER)
RETURN NUMBER IS
BEGIN
INSERT INTO empregadon(cd_empregado, nm_empregado,
vl_salario, vl_comissao, cd_depart)
VALUES(99, 'Esmeraldo', 8800.47, NULL, 10);
RETURN (p_sal + 100);
END;

UPDATE empregadon
SET vl_salario = dml_call_sql(2000)
WHERE cd_empregado = 130;

29
Notação Nomeada e Combinada em SQL: Exemplo
CREATE OR REPLACE FUNCTION f(
p_parameter_1 IN NUMBER DEFAULT 1,
p_parameter_5 IN NUMBER DEFAULT 5)
RETURN NUMBER
IS
v_var number;
BEGIN
v_var := p_parameter_1 + (p_parameter_5 * 2);
RETURN v_var;
END f;
/

SELECT f(p_parameter_5 => 10) FROM DUAL;

30
O Que São Triggers?

• Um trigger é um bloco PL/SQL


armazenado no banco de dados e
acionado (executado) em resposta a um
evento especificado.
• O Oracle database executa
automaticamente um trigger quando
condições específicas ocorrem.
Definindo Triggers

Um trigger pode ser definido na tabela, view, esquema


(proprietário do esquema) ou banco de dados (todos os
usuários).

Tabela Esquema
(proprietário)

View Banco de dados (Todos os usuários)


Tipos de Eventos de Trigger

Você pode gravar triggers que são acionados sempre que uma
das seguintes operações ocorra no banco de dados:
• Uma instrução DML (database manipulation) (DELETE,
INSERT, ou UPDATE).
• Uma instrução DDL (database definition) (CREATE, ALTER,
ou DROP).
• Uma operação em banco de dados como SERVERERROR,
LOGON, LOGOFF, STARTUP, ou SHUTDOWN.
Triggers de Aplicação e Banco de Dados

• Trigger de banco de dados (abordado neste curso):


– É acionado sempre que um evento DML, DLL ou de sistema
ocorre em um esquema ou banco de dados
• Trigger de aplicação:
– É disparado sempre que ocorre um evento em determinada
aplicação

Trigger de aplicação Trigger de Banco de Dados


Cenários de Aplicações de Negócios
para a Implementação de Triggers
Você pode usar triggers para:
• Segurança
• Auditoria
• Integridade dos dados
• Integridade referencial
• Replicação de tabelas
• Cálculo automático de dados derivados
• Log de eventos
Tipos de Trigger Disponíveis

• Triggers DML simples


– BEFORE
– AFTER
– INSTEAD OF
• Triggers compostos
• Triggers não DML
– Triggers de evento DDL
– Triggers de evento de banco de dados
Tipos de Eventos de Trigger e Trigger Body

• Um tipo de evento de trigger determina qual instrução


DML faz com que o trigger seja executado. Os eventos
possíveis são:
– INSERT
– UPDATE [OF column]
– DELETE
• Um trigger body determina qual ação é executada e é um
bloco PL/SQL ou uma CALL a um procedure.
Criando Triggers DML Usando a Instrução
CREATE TRIGGER
CREATE [OR REPLACE] TRIGGER trigger_name
timing –- when to fire the trigger
event1 [OR event2 OR event3]
ON object_name
[REFERENCING OLD AS old | NEW AS new]
FOR EACH ROW –- default is statement level trigger
WHEN (condition)]]
DECLARE]
BEGIN
... trigger_body –- executable statements
[EXCEPTION . . .]
END [trigger_name];

timing = BEFORE | AFTER | INSTEAD OF

event = INSERT | DELETE | UPDATE | UPDATE OF column_list


Especificando o Acionamento do Trigger
(Tempo de Execução)
Você pode especificar o momento de execução do trigger,
disparando a ação do trigger antes ou depois da instrução
responsável pelo seu acionamento:
• BEFORE: Executa o trigger body antes do evento DML de
acionamento do trigger em uma tabela.
• AFTER: Executa o trigger body depois do evento DML de
trigger em uma tabela.
• INSTEAD OF: Executa o trigger body em vez da instrução
responsável pelo acionamento do trigger. Essa opção é
usada em views que não podem ser modificadas de outra
maneira.
Triggers de Nível de Instrução
Versus Triggers de Nível de Linha

Triggers de Nível de Instrução Triggers de Nível de Linha

É o default ao se criar um trigger Use a cláusula FOR EACH ROW ao criar


um trigger.

É executado uma vez para o evento de É executado uma vez para cada linha
trigger afetada pelo evento de trigger

É disparado uma vez mesmo que Não será executado se nenhuma linha
nenhuma linha seja afetada for afetada pelo evento de trigger
Sequência de Acionamento de Trigger:
Manipulação de uma Única Linha
Use a seguinte sequência para disparar um trigger em uma
tabela quando uma única linha for manipulada:
INSERT INTO departments
(cd_depart,department_name, location_id)
VALUES (400, 'CONSULTING', 2400);

Trigger de
instruçãoBEFORE

... Trigger de linhaBEFORE

Trigger de linhaAFTER

Trigger de instrução AFTER


Sequência de Acionamento de Triggers:
Manipulação de Várias Linhas
Use a seguinte sequência para disparar um trigger em uma
tabela quando várias linhas forem manipuladas:
UPDATE empregadon
SET vl_salario = vl_salario * 1.1
WHERE cd_depart =30;

Trigger de
instruçãoBEFORE
Trigger de linhaBEFORE
Trigger de linhaAFTER
...
Trigger de linhaBEFORE
Trigger de linhaAFTER
...

Trigger de instrução AFTER


Criando um Trigger de Instrução DML Exemplo:
SECURE_EMP

INSERT INTO
empregadon...;

Instrução DML aciona Tabela


trigger empregadon
Aplicação
TriggerSECURE_EMP

CREATE OR REPLACE TRIGGER secure_emp


BEFORE INSERT ON empregadon
BEGIN
IF (TO_CHAR(SYSDATE,'DY') IN ('SAT','SUN')) OR
(TO_CHAR(SYSDATE,'HH24:MI')
NOT BETWEEN '08:00' AND '18:00') THEN
RAISE_APPLICATION_ERROR(-20500, 'Inclusão na '
||' tabela empregadon apenas '
||' durante o horário comercial.');
END IF;
END;
Testando o Trigger SECURE_EMP

INSERT INTO empregadon (cd_empregado, nm_empregado,


vl_salario, cd_depart)
VALUES (300, 'Epaminondas', 4500, 60);
Usando Predicados Condicionais

CREATE OR REPLACE TRIGGER secure_emp BEFORE


INSERT OR UPDATE OR DELETE ON empregadon
BEGIN
IF (TO_CHAR(SYSDATE,'DY') IN ('SAT','SUN')) OR
(TO_CHAR(SYSDATE,'HH24')
NOT BETWEEN '08' AND '18') THEN
IF DELETING THEN RAISE_APPLICATION_ERROR(
-20502, 'Só é possível apagar no horário comercial.');
ELSIF INSERTING THEN RAISE_APPLICATION_ERROR(
-20500,’Só é possível incluir no horário comercial.');
ELSIF UPDATING('vl_salario') THEN
RAISE_APPLICATION_ERROR(-20503, 'Fora do horário.');
ELSE RAISE_APPLICATION_ERROR(-20504, 'Fechamos');
END IF;
END IF;
END;
Criando um Trigger de Linha DML
CREATE OR REPLACE TRIGGER restrict_vl_salario
BEFORE INSERT OR UPDATE OF vl_salario ON empregadon
FOR EACH ROW
BEGIN
IF NOT (:NEW.job_id IN ('AD_PRES', 'AD_VP'))
AND :NEW.vl_salario > 15000 THEN
RAISE_APPLICATION_ERROR (-20202,
'Employee cannot earn more than $15,000.');
END IF;
END;

UPDATE empregadon
SET vl_salario = 15500
WHERE nm_empregado = 'Russell';
Usando os Qualificadores OLD e NEW

• Quando um trigger de nível de linha é acionado, o


mecanismo de runtime PL/SQL cria e preenche duas
estruturas de dados:
– OLD: Armazena os valores originais do registro processado
pelo trigger
– NEW: Contém os novos valores
• NEW e OLD têm a mesma estrutura que um registro
declarado usando %ROWTYPE na tabela à qual o trigger
é associado.
Operações de Dados Valor Antigo Novo Valor
INSERT NULL Valor inserido
UPDATE Valor antes da atualização Valor após a atualização
DELETE Valor antes da deleção NULL
Usando Qualificadores OLD e NEW: Exemplo
CREATE TABLE audit_emp (
user_name VARCHAR2(30),
time_stamp date,
id NUMBER(6),
old_nm_empregado VARCHAR2(25),
new_nm_empregado VARCHAR2(25),
old_title VARCHAR2(10),
new_title VARCHAR2(10),
old_vl_salario NUMBER(8,2),
new_vl_salario NUMBER(8,2) )
/
CREATE OR REPLACE TRIGGER audit_emp_values
AFTER DELETE OR INSERT OR UPDATE ON empregadon
FOR EACH ROW
BEGIN
INSERT INTO audit_emp(user_name, time_stamp, id,
old_nm_empregado, new_nm_empregado, old_title,
new_title, old_vl_salario, new_vl_salario)
VALUES (USER, SYSDATE, :OLD.cd_empregado,
:OLD.nm_empregado, :NEW.nm_empregado, :OLD.job_id,
:NEW.job_id, :OLD.vl_salario, :NEW.vl_salario);
END;
Usando os Qualificadores OLD e NEW:
Exemplo
INSERT INTO empregadon (cd_empregado, nm_empregado,
job_id, vl_salario, email, hire_date)
VALUES (999, 'Temp emp', 'SA_REP', 6000, 'TEMPEMP',
TRUNC(SYSDATE))
/
UPDATE empregadon
SET vl_salario = 7000, nm_empregado = 'Smith'
WHERE cd_empregado = 999
/
SELECT *
FROM audit_emp;
Usando a Cláusula WHEN para Acionar um
Trigger de Linha com Base em uma Condição

CREATE OR REPLACE TRIGGER derive_vl_comissao


BEFORE INSERT OR UPDATE OF vl_salario ON empregadon
FOR EACH ROW
WHEN (NEW.job_id = 'SA_REP')
BEGIN
IF INSERTING THEN
:NEW.vl_comissao := 0;
ELSIF :OLD.vl_comissao IS NULL THEN
:NEW.vl_comissao := 0;
ELSE
:NEW.vl_comissao := :OLD.vl_comissao+0.05;
END IF;
END;
/
Resumo do Modelo de Execução de Triggers

1. Execute todos os triggers BEFORE STATEMENT.


2. Execute um loop para cada linha afetada pela instrução
SQL:
a. Execute todos os triggers BEFORE ROW dessa linha.
b. Execute a instrução DML e a verificação da constraint de
integridade nessa linha.
c. Execute todos os triggers AFTER ROW dessa linha.
3. Execute todos os triggers AFTER STATEMENT.
Implementando uma Constraint
de Integridade com um Trigger After
-- Integrity constraint violation error –2991 raised.
UPDATE empregadon SET cd_depart = 999
WHERE cd_empregado = 170;

CREATE OR REPLACE TRIGGER employee_dept_fk_trg


AFTER UPDATE OF cd_depart ON empregadon
FOR EACH ROW
BEGIN
INSERT INTO departments VALUES(:new.cd_depart,
'Dept '||:new.cd_depart, NULL, NULL);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
NULL; -- mask exception if department exists
END;
/

-- Successful after trigger is fired


UPDATE empregadon SET cd_depart = 999
WHERE cd_empregado = 170;
Triggers INSTEAD OF

Aplicação

INSERT INTO my_view


. . . ;
INSERT

TABELA 1

Trigger INSTEAD OF
UPDATE

MY_VIEW
TABELA 2
Criando um Trigger INSTEAD OF: Exemplo

INSERT INTO emp_details


VALUES (9001,'ABBOTT',3000, 10, 'Administration');

INSERT na
INSTEAD OF INSERT
tabela
em EMP_DETAILS NEW_EMPS
1

3
UPDATE tabela
View EMP_DETAILS NEW_DEPTS
Criando um Trigger INSTEAD OF para
Executar DML em Views Complexas
CREATE TABLE new_emps AS
SELECT cd_empregado,nm_empregado,vl_salario,cd_depart
FROM empregadon;

CREATE TABLE new_depts AS


SELECT d.cd_depart,d.department_name,
sum(e.vl_salario) dept_sal
FROM empregadon e, departments d
WHERE e.cd_depart = d.cd_depart;

CREATE VIEW emp_details AS


SELECT e.cd_empregado, e.nm_empregado, e.vl_salario,
e.cd_depart, d.department_name
FROM empregadon e, departments d
WHERE e.cd_depart = d.cd_depart
GROUP BY d.cd_depart,d.department_name;
O Status de um Trigger

Um trigger existe em dois modos distintos:


• Ativado: O trigger executa sua ação se uma instrução de
trigger for emitida e a restrição de trigger (se houver) for
avaliada como verdadeira (default).
• Desativado: O trigger não executa sua ação mesmo se
uma instrução de trigger for emitida e a restrição de trigger
(se houver) for avaliada como verdadeira.
Há algo que gostariam que explicasse melhor?

Você também pode gostar