Você está na página 1de 32

Oracle Database 11g: Fundamentos de PL/SQL

Carga horária: 32 horas


Objetivos
 Criar constante padrão e exceção;
 Escrever e invocar subprogramas;
 Controlar privilégios em tempo de execução de subprogramas;
 Trabalhar com transação autônoma.
Padronizando constantes e exceções
 Constantes e exceções são tipicamente implementadas usando o
corpo do package e acessadas via área de especificação do
package.
 Padronização auxilia para:
 Desenvolvimento de programas consistentes;
 Possibilita reuso de código;
 Facilita a manutenção de código.
 Padronização de:
 Nome de exceção;
 Definição de constante.
Criando um package padrão de
exceção
 Criando um nome padrão para exceções a serem
implementados nos subprogramas.

CREATE OR REPLACE PACKAGE pkg_exception IS


e_db_link_err EXCEPTION;
e_sequence_nm_err EXCEPTION;
PRAGMA EXCEPTION_INIT (e_db_link_err, -2071); --ORA-02071:
error initializing capabilities for remote database string
PRAGMA EXCEPTION_INIT (e_sequence_nm_err, -2277); --ORA-
02277: invalid sequence name
-- Partial code.
END pkg_exception;
Padronizando manipulação de exceção
 Considere escrever nos subprogramas a manipulação de
exceção usando:
 SQLCODE para identificar o erro ocorrido e SQLERRM visando
identificar a mensagem retornada no erro;

 Manipule as exceções que podem ocorrer em tempo de


execução usando parâmetros para identificar facilmente:
 O procedimento que lançou o erro;
 Verificar a linha que o erro ocorreu;
 Use RAISE_APPLICATION_ERROR com o terceiro
parâmetro definido como TRUE.
Criando um package padrão de
CONSTANT
 Defina um package de CONSTANT para os subprogramas
que não permitam alteração de valor da variável.

 Converter essas variáveis para constantes proporciona


redução no tempo de manutenção.

CREATE OR REPLACE PACKAGE pkg_constant IS


c_desconto_irpf CONSTANT NUMBER(3) := 0.11;
c_pagto_a_vista CONSTANT VARCHAR(2) := 'A VISTA';
c_menor_salario CONSTANT NUMBER := 1200;
c_aumento_salario CONSTANT NUMBER := 500;
END pkg_constant;
Criando um package padrão de
CONSTANT (Exemplo)
 Realizando atualização de salário com valor definido no package de
CONSTANT.

UPDATE employees
SET salary = (salary + pkg_constant.c_aumento_salario)
WHERE salary <= 2400;
Subprograma Local
 Um subprograma local é uma procedure ou função definida no final da
seção declarativa do subprograma;

 Utilizado para desenvolvimento de subprograma que necessite de


uma estrutura auxiliar, porém sem a estruturar em package.
Subprograma Local
CREATE OR REPLACE PROCEDURE descontar_dano_produto(p_id_empregado
employees.employee_id%TYPE)
IS
v_empregado employees%ROWTYPE;
v_salario employees.salary%TYPE;
FUNCTION verificar_desconto(p_salario employees.salary%TYPE) RETURN
NUMBER IS
v_desconto NUMBER;
BEGIN
IF p_salario <= 3000 THEN
v_desconto := (p_salario * 0.02);
ELSE
v_desconto := (p_salario * 0.04);
END IF;
RETURN v_desconto;
END;
BEGIN
SELECT salary INTO v_salario
FROM employees
WHERE employee_id = p_id_empregado;
dbms_output.put_line('Desconto do empregado pelo dano produto: '
|| verificar_desconto(v_salario) || ' Salário: ' || v_salario);
END;
Definer’s Rights vs Invoker’s Right
Definer’s rights: Invoker’s rights
 O programa executa com  O programa executa com os
privilégios do usuário que privilégios do usuário que o criou;
criou;  O usuário ou esquema que
invocar a procedure necessitará de
 O usuário ou esquema que
permissões em todos os objetos
invoca a procedure não precisa usados na procedure.
de privilégios sobre os objetos
que o subprograma acessa. Ele * Obs: As permissões serão
precisa somente do privilégio conforme o tipo de manipulação
de EXECUTE sobre ela. DML definida nos objetos
acessados pela procedure.
Especificando Invoker’s Rights
AUTHID to CURRENT_USER
 Quando usados com stand-alone functions, procedures ou
packages:
 Nomes usados em consultas, DML, Native Dynamic SQL e
DBMS_SQL packages são resolvidos com invoker’s esquema;

 Invocar outros packages, functions e procedures são resolvidos


com definer’s esquema.
CREATE OR REPLACE PROCEDURE add_dept(
p_name VARCHAR2) AUTHID CURRENT_USER IS
BEGIN
INSERT INTO departments
VALUES (departments_seq.NEXTVAL, p_name, NULL,
NULL);
END;
Especificando Invoker’s Rights
AUTHID to CURRENT_USER
 Criar um usuário de teste para acessar a procedure criada:
CREATE USER scottXX IDENTIFIED BY scott
ACCOUNT UNLOCK;

 Conceder permissão de execução para o usuário criado:


GRANT EXECUTE ON add_dept TO scott;

 Acessar o banco de dados com o usuário criado e invocar a


procedure:
EXECUTE add_dept('TESTE');
Transação Autônoma
 Transação independente iniciada a partir de uma transação
principal;
 São especificadas com PRAGMA
AUTONOMOUS_TRANSACTION.
Característica da Transação
Autônoma
 São independentes da transação principal (PL/SQL que invoca);
 Suspende a chamada da transação até que a transação
autônoma seja completada;
 São é uma transação aninhada;
 Não sofre ROLLBACK se a transação principal executar um
ROLLBACK;
 São inicializadas e finalizadas como um programa individual e
não são blocos anônimos.
Transação Autônoma
Preparação do ambiente
 Criar tabela:
CREATE TABLE vendas(
id NUMBER,
produto VARCHAR2(200),
valor NUMBER,
qtde NUMBER);

CREATE TABLE log_vendas(


data DATE,
cliente VARCHAR2(100));

 Criar sequence:
CREATE SEQUENCE vendas_seq;
Transação Autônoma
Preparação do ambiente (cont.)
 Criar procedure principal (main):

CREATE OR REPLACE PROCEDURE grava_vendas(


p_produto vendas.produto%TYPE,
p_valor vendas.valor%TYPE DEFAULT 10.00,
p_qtde vendas.qtde%TYPE DEFAULT 1) IS
BEGIN
INSERT INTO vendas VALUES(vendas_seq.NEXTVAL,
p_produto, p_valor, p_qtde);
lanca_horario_vendas;
END;
Transação Autônoma
Preparação do ambiente (cont.)
 Criar procedure autônoma:
CREATE OR REPLACE PROCEDURE lanca_horario_vendas (
p_nome_cliente VARCHAR2 DEFAULT 'Desconhecido') IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO log_vendas VALUES(SYSDATE,
p_nome_cliente);
--COMMIT;
END;

 Invocar procedure principal (main):


EXECUTE grava_vendas('BATATA');
ROLLBACK;

 Consultar as tabelas para analisar os resultados.


Usando o Hint NOCOPY
 Permite passar parâmetros do tipo OUT e IN OUT por
referência e não por valor;
 Melhora o desempenho reduzindo a sobrecarga ao passar
parâmetros.
Efeitos de usar o Hint NOCOPY
 Uma exceção não é manipulada:
 Não é possível saber os valores reais quando se utiliza o
parâmetro NOCOPY;
 Uma modificação incompleta não recebe rollback.
 Chamada remota de procedures permite passagem de
parâmetros somente por valor.
Situações em que o compilador
ignora o Hint NOCOPY
 O hint NOCOPY não tem efeito se:
 Passagem de parâmetro tipo: atual
 Se o elemento é um associate array (Index –by tables);
 É uma constraint (por exemplo: por escala ou NOT NULL);
 Os parâmetros formais são registrosm em que um ou ambos
os registros foram declarados utilizando %ROWTYPE ou TYPE
e restrições diferentes nos registros.
 Requer uma conversão de tipo de dados implícita.
 O subprograma é envolvido com uma chamada externa ou
chamada remota de procedures.
Usando o Hint PARALLEL_ENABLE
 Pode ser usado em funções como um hint de otimização;
 Indica que uma função pode ser utilizada em consulta ou DML
paralelizada.
Usando Cross-Session PL/SQL
Função com Result Cache
 Cada vez que uma função PL/SQL é chamada com parâmetros
de valores diferentes, esses parâmetros e os resultados são
armazenados em cache;
 O result cache da função é armazenado na Área Global
Compartilhada – SGA, tornando-o disponível para qualquer
sessão que acessa a aplicação;
 Consequentemente chamada a mesma função com os mesmos
parâmetros serão retornadas a partir do result cache;
 Performance e escalabilidade são melhoradas;
 O result cache é utilizado para funções que são chamadas
frequentemente e são dependentes de informações que não
mudam com tanta frequência.
Habilitando Result Cache para
uma função
 Inclua a cláusula RESULT_CACHE no seguinte:
 Na declaração da função;
 Na definição da função.

 Inclua uma cláusula opcional RELIES_ON para especificar


qualquer tabela ou view que o resultado da função dependa.
Declarando e definindo uma função
com Result Cache: Exemplo
Usando a cláusula DETERMINISTIC
com funções
 Especifique DETERMINISTIC para indicar que a função retornará
o mesmo valor como resultado para todas as vezes que ela for
chamada com os mesmos valores para os seus argumentos;
 Isso ajuda o otimizador a evitar chamadas redundantes a
funções;
 Se uma função foi chamada anteriormente com os mesmos
argumentos, o otimizador pode optar por usar o resultado
retornado anteriormente;
 Não especifique DETERMINISTIC para uma função cujo
resultado depende do estado de variáveis de sessão ou objetos
de esquema.
Usando a cláusula RETURNING
 Melhora o desempenho retornando os valores da coluna de instruções
INSERT, UPDATE e DELETE;
 Assim, não há necessidade de executar um SELECT para identificar os
valores.
CREATE OR REPLACE PROCEDURE atualiza_salario (
p_employee_id employees.employee_id%TYPE)
IS
v_last_name employees.last_name%TYPE;
v_salary employees.salary%TYPE;
BEGIN
UPDATE employees
SET salary = salary * 1.1
WHERE employee_id = p_employee_id
RETURNING last_name, salary INTO v_last_name, v_salary;
dbms_output.put_line('Last name: ' || v_last_name || ' -
Salário: '|| v_salary);
END;
Usando BULK com Binds
 Com Binds é possível definir um array de valores com uma
simples operação, ao invés de executar loop para executar
FETCH, INSERT, UPDATE e DELETE várias vezes.
Bulk Binding: Sintaxe
 A instrução FORALL é uma PL/SQL engine para realizar bulk bind
dentro de uma coleção antes de enviar os dados para a SQL
engine.

 A instrução BULK COLLECTION instrui a SQL engine a carregar os


dados na coleção.
Bulk Binding FORALL: Exemplo
CREATE OR REPLACE PROCEDURE aumento_salario (
p_porc_aumento NUMBER)
IS
TYPE numlist_type IS TABLE OF NUMBER INDEX BY
BINARY_INTEGER;
v_id numlist_type;
BEGIN
v_id(1) := 100;
v_id(2) := 102;
v_id(3) := 107;
v_id(4) := 109;
v_id(5) := 111;
FORALL i IN v_id.FIRST .. v_id.LAST
UPDATE employees
SET salary = ((1 + p_porc_aumento/100) * salary)
WHERE employee_id = v_id(i);
END;
Usando BULK COLLECT INTO com consultas
 A instrução SELECT suporta o uso de BULK COLLECT INTO na sua
sintaxe.
CREATE OR REPLACE PROCEDURE verifica_departmaneto (
p_localidade NUMBER)
IS
TYPE depto_tab_type IS TABLE OF departments%ROWTYPE;
v_depts depto_tab_type;
BEGIN
SELECT * BULK COLLECT INTO v_depts
FROM departments
WHERE location_id = p_localidade;

FOR i IN 1 .. v_depts.COUNT LOOP


dbms_output.put_line(v_depts(i).department_id || ' - ' ||
v_depts(i).department_name);
END LOOP;
END;
Usando BULK COLLECT INTO com Cursor
 A instrução FETCH suporta o uso de BULK COLLECT INTO na sua
sintaxe.
CREATE OR REPLACE PROCEDURE verifica_departmaneto (
p_localidade NUMBER)
IS
CURSOR cur_dept IS
SELECT *
FROM departments
WHERE location_id = p_localidade;
TYPE depto_tab_type IS TABLE OF cur_dept%ROWTYPE;
v_depts depto_tab_type;
BEGIN
OPEN cur_dept;
FETCH cur_dept BULK COLLECT INTO v_depts;
CLOSE cur_dept;
FOR i IN 1 .. v_depts.COUNT LOOP
dbms_output.put_line(v_depts(i).department_id || ' - ' ||
v_depts(i).department_name);
END LOOP;
END;
Usando BULK COLLECT INTO com RETURNING
CREATE OR REPLACE PROCEDURE atualiza_comissao_sal (
p_comissao NUMBER)
IS
TYPE list_id_emp_type IS TABLE OF NUMBER;
TYPE salario_emp_type IS TABLE OF employees.salary%TYPE INDEX
BY BINARY_INTEGER;
v_ids_emp list_id_emp_type :=
list_id_emp_type(101,102,107,109,111);
v_new_salario salario_emp_type;
BEGIN
null;
FORALL i IN v_ids_emp.FIRST .. v_ids_emp.LAST
UPDATE employees
SET salary = (salary * p_comissao) + salary
WHERE employee_id = v_ids_emp(i)
RETURNING salary BULK COLLECT INTO v_new_salario;
FOR i IN 1 .. v_new_salario.COUNT LOOP
dbms_output.put_line('Salary: ' || v_new_salario(i));
END LOOP;
END;

Você também pode gostar