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 o
privilégios do usuário que criou;
criou;
 O usuário ou esquema que
 O usuário ou esquema invocar a procedure
que invoca a procedure necessitará de permissões em
todos os objetos usados na
não precisa de privilégios procedure.
sobre os objetos que o
subprograma acessa. Ele * Obs: As permissões serão
conforme o tipo de
precisa somente do manipulação DML definida nos
privilégio de EXECUTE objetos acessados pela
sobre ela. procedure.
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;
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.
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