apostila plsql

38
APOSTILA DE ORACLE PL/SQL

Upload: adriano-ramos

Post on 22-Jan-2016

62 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Apostila PLSQL

APOSTILA DE

ORACLE PL/SQL

Page 2: Apostila PLSQL

PL/SQL A linguagem PL/SQL (Procedural Language/SQL) é uma extensão de linguagem procedural da Oracle para SQL, que incorpora recursos de programação, tais como:

• Declaração de variáveis e tipos pré-definidos; • Estruturas de seleção e repetição;

• Procedimentos e funções.

Além de aceitar a manipulação de dados, ela também permite que as instruções de consulta da linguagem SQL sejam incluídas em unidades procedurais de código e estruturadas em blocos, tor-nando a linguagem SQL uma linguagem avançada de processamento de transações. A linguagem PL/SQL é estruturada em blocos, os programas podem ser divididos em blocos lógi-cos. Um bloco PL/SQL é dividido em três seções:

DECLARATIVA (opcional) - Seção destinada à declaração das variáveis, cursores e exce-ções que serão utilizadas no bloco; EXECUTÁVEL (obrigatória) - também conhecida como corpo do programa, área onde são descritos os passos necessários para realização da tarefa. Podem ser utilizadas instruções SQL e/ou PL/SQL; TRATAMENTO DE EXCEÇÕES (opcional) - destinada ao tratamento das exceções gera-das no bloco; devem ser descritas as ações a serem desempenhadas quando ocorrerem erros.

1.1. Blocos Anônimos Os blocos anônimos não ficam armazenados na base de dados e não podem ser chamados por outros blocos PL/SQL. Eles devem ser compilados a cada utilização. Pode-se incorporar um bloco anônimo em uma aplicação ou pode-se executá-lo interativamente no SQL*Plus. Exemplo da estrutura de um bloco em PL/SQL: DECLARE

v_variavel varchar2(5); BEGIN

Select nome_coluna into v_variavel from

EXCEPTION nome_tabela;

When <exception_name> then ... (procedimentos a serem executados quando uma determinada exceção correr.) o

END; Sobre o código:

• As palavras chave DECLARE, BEGIN e EXCEPTION não são sucedidas de ponto e vírgula (;), apenas as demais instruções;

• A palavras-chave BEGIN e END são obrigatórias.

• Deve-se utilizar uma barra (/) para executar o bloco anônimo PL/SQL no buffer do S-

QL*Plus.

Page 3: Apostila PLSQL

1.1.1. Operadores e delimitadores Operador Descrição Operador Descrição

+ Adição % Atributo * Multiplicação . Separador de componentes - Subtração ‘ Cadeia de caracteres / Divisão : Variável de ligação ** Exponenciação := Atribuição || Concatenação .. Intervalo = Igualdade -- Comentário de linha > Comparação – maior que << Início do texto do label (etiqueta) < Comparação – menor que >> Delimitador de final do texto do label (etiqueta)

>= Comparação – maior ou igual ; Finalizador de instrução <= Comparação – menor ou igual , Separador de itens

~= ou ^= Comparação – diferente “ Delimitador de cadeia de caracteres (mensa-gens)

<> ou != Comparação – diferente /* Início de comentário de linha ( Início de expressão */ Delimitador de fim de comentário de linha ) Fim expressão

1.1.2. Variáveis Os dados podem ser armazenados temporariamente em uma ou mais variáveis e podem ser utili-zadas para:

Manipulação de valores armazenados - As variáveis podem ser usadas para cálculo e manipulação de outros dados sem acessar o banco de dados, ou seja, após os valores em memória não há necessidade de outros acessos para complemento da informação já arma-zenada; Reutilização - Quando declaradas, podem ser usadas repetidamente em uma aplicação, referenciando-as em outras instruções, incluindo outras instruções declarativas; Facilitar a manutenção – Pode-se declarar variáveis baseadas na estrutura das colunas das tabelas ou em outras variávies (%TYPE e %ROWTYPE). Se uma definição subjacente for alterada, a declaração da variável é atualizada em tempo de execução. Isso permite a independência dos dados, reduz custos de manutenção e permite que os programas se adaptem de acordo com as alterações realizadas no banco de dados; Passar valores aos subprogramas PL/SQL através de parâmetros; Exibir os resultados em um bloco PL/SQL através de variáveis de saída.

A declaração e a inicialização das variáveis é feita na seção declarativa de qualquer subprograma, pacote ou bloco PL/SQL. As declarações alocam espaço de armazenamento para um valor, espe-cificam seus tipos de dados e nomeiam a localização de armazenamento para que se possa refe-renciá-los. As declarações poderão também atribuir um valor inicial e impor a restrição NOT NULL. ATENÇÃO: Ao Atribuir novos valores às variáveis na seção executável o valor existente da variá-vel é substituído pelo novo e é necessário declarar uma variável antes de referenciá-la em outras instruções, incluindo outras instruções declarativas.

Page 4: Apostila PLSQL

1.1.3. Tipos de Variáveis Todas as variáveis PL/SQL têm um tipo de dados que especifica o formato de armazenamento, restrições e uma faixa válida de valores. A linguagem PL/SQL suporta quatro categorias destes:

Escalares - armazenam um único valor. Os principais tipos de dados são aqueles que cor-respondem aos tipos de coluna nas tabelas do Oracle Server, por exemplo vachar2, num-ber, char, entre outros; a linguagem PL/SQL também suporta variáveis booleanas; Compostos – comporta o armazenamento de diferentes valores. Os tipos compostos em PL/SQL são registro, tabelas e matrizes; Referenciais - armazenam valores, chamados de indicadores, que designam outros itens de programa. Um exemplo de tipos referenciais é o REF CURSOR.

Declaração de Variáveis Sintaxe:

identificador [CONSTANT] tipo de dados [NOT NULL] [:= valor para inicialização | expr default]

onde,

Identificador: é o nome da variável; Os identificadores não devem ter mais de 30 carac-teres. O primeiro caracter deve ser uma letra; os demais podem ser letras, números ou símbolos especiais; Não devem ser palavras reservadas nem possuir espaços entre os caracteres.

CONSTANT: restringe as variáveis para que o seu valor não possa ser alterado; as

constantes devem ser inicializadas tipo de dados são tipos de dados escalares, compostos, referenciais ou LOB NOT NULL indica preenchimento obrigatório (variáveis NOT NULL devem ser iniciali-

zadas). expr é uma expressão PL/SQL que pode ser uma literal, uma outra variável ou

uma expressão que envolve operadores e funções. ATENÇÃO:

• Para inicializar a variável utiliza-se operador de atribuição (:=) ou a palavra reservada DE-FAULT. Se não for atribuído um valor inicial, a nova variável conterá NULL por default.

• Não é aconselhável identificar uma variável com nome igual ao nome das colunas de ta-bela usadas no bloco. Se as variáveis PL/SQL ocorrerem nas instruções SQL e tiverem o mesmo nome que uma coluna, o Oracle Server supõe que é a coluna que está sendo refe-renciada.

1.1.3.1 Tipos de Dados Escalares Um tipo de dado escalar armazena um valor único e não possui componentes internos. Os tipos de dados escalares podem ser classificados em quatro categorias: número, caractere, data e boo-leano. Os tipos de dados de caractere e número possuem subtipos que associam um tipo básico a uma restrição. Por exemplo, INTEGER e POSITIVE são subtipos do tipo básico NUMBER. Segue abaixo exemplo de tipos de Dados Escalares Básicos:

Page 5: Apostila PLSQL

Tipo de dado Descrição VARCHAR2(tamanho) Caracteres com tamanho variável com até 32.767 bytes; não há

tamanho default para estas variáveis. NUMBER(tamanho, precisão) Números reais ou inteiros DATE Datas e horas entre os períodos de 4712 A.C. e 9999 D.C. CHAR(tamanho) Caracteres de tamanho fixo até 32.767 bytes; tamanho default 1

byte. LONG Caracteres com tamanho variável de até 32.760 bytes, a largura

máxima é de 2.147.483.647 bytes LONG RAW Dados binários e strings de byte de até 32.760 bytes; estes da-

dos não são interpretados pelo PL/SQL BOOLEAN Um de três possíveis valores: TRUE, FALSE ou NULL BINARY_INTEGER Números inteiros entre –2.147.483.647 e 2.147.483.647 PLS_INTEGER Números inteiros entre –2.147.483.647 e 2.147.483.647; estes

valores requerem menos armazenamento e são mais rápidos que os valores NUMBER e BINARY_INTEGER

Exemplos:

v_nascimento date; v_data date := sysdate + 7; --declaração de variável e inicialização partir de uma operação aritmética à

v_codigo number(2) not null := 10; -- declaração da variável com a restrição de preenchimento obrigatório, neste caso é preciso atribuir o valor inicial v_UF varchar2(2) := ‘SP’; -- declaração e inicialização da variável com o valor SP; observe que os literais devem ser informados entre apóstrofos (‘ ‘) v_Loc varchar2(2) default ‘RJ’; -- declaração da variável cujo valor efault é RJ. d

v_teste_logico boolean := (v_valor1 < v_valor2); -- declaração da variável v_teste_logico que será inicializada com o resultado da xpressão (v_valor1 < v_valor2) e

c_const constant number := 54; -- declaração da constante que está sendo inicializada.

O atributo %TYPE pode ser utilizado para declarar variáveis com a mesma estrutura de uma tabela ou de uma variável já existente. Sintaxe:

identificador [CONSTANT] {tabela.coluna%type | variavel%type} [NOT NULL] [:= valor para inicialização | expr default]

Exemplos:

v_nome EMPR_NOME_DS%type; -- declaração da variável com a mesma estrutura da coluna EMPR_NOME_DS da tabela EMPR. v_balance number(7,2); v_min_balance v_balance%type; -- declaração da variável com a mesma estrutura da variável declarada anteriormente.

Page 6: Apostila PLSQL

ATENÇÂO: É uma boa prática de programação a adoção de uma convenção de nomeação para variáveis, por expl: o prefixo v_ representa uma variável; c_ representa uma constante.

1.1.4. Variáveis de Substituição Além das variáveis declaradas no Bloco PL/SQL existem as variáveis de substituição e de ligação. O código PL/SQL não tem capacidade de entrada/saída própria, para isso pode-se utilizar o ambi-ente no qual o código PL/SQL estiver sendo executado para passar valores para o bloco, estes va-lores são passados por meio das variáveis de substituição. ATENÇÃO: Ao utilizar as variáveis de substituição os valores são substituídos no bloco PL/SQL antes que esse bloco seja executado. Por isso, não é possível substituir os diferentes valores para as variáveis de substituição usando um loop. Exemplo:

ACCEPT p_nome PROMPT ‘Digite o nome do funcionário...’ ACCEPT p_sal_mes PROMPT ‘Digite o valor do salario...’

O comando accept indica que o valor para a variável de substituição p_nome e p_sal_mes serão fornecidos pelo teclado. O comando PROMPT indica a mensagem que será exibida para orientar o usuário quanto ao valor a ser digitado. Para atribuir os valores das variáveis de substituição para as variáveis PL/SQL é necessário a utilização do “&” (“E” comercial). Exemplo:

Declare v_nome varchar2(30) := ‘&p_nome’; v_sal number(9,2) := &p_sal_mes;

1.1.5. Variáveis de ligação Para declarar uma variável de ligação no ambiente SQL*Plus, utiliza-se o comando VARIABLE. Exemplo:

SQL> VARIABLE g_sal_anual NUMBER

Estas variáveis podem ser declaradas no prompt do SQL ou fora do bloco PL/SQL (antes do declare ou depois da “/”). Para utilizar estas variáveis no bloco PL/ SQL deve-se precedê-las de ‘:’ (dois pontos), para que sejam distinguidas das variáveis PL/SQL: Exemplo:

:g_sal_anual := v_sal * 12;

A exibição dos valores armazenados nestas variáveis pode ser feita por meio do comando PRINT. Exemplo:

PRINT g_sal_anual

Exemplo 1: Calcular o salário anual de dado funcionário com base no salário mensal fornecido pe-lo usuário. Exibir o resultado.

Page 7: Apostila PLSQL

VARIABLE g_sal_anual NUMBER ACCEPT p_nome PROMPT ‘Nome do funcionario...: ’ ACCEPT p_sal_mes PROMPT ‘Valor do salario...: ’

Instrução SQL

Declare v_nome varchar2(30) := ‘&p_nome’; v_sal number(9,2) := &p_sal_mes; Begin :g_sal_anual := v_sal * 12; END; /

Bloco PL/SQL

PRINT g_sal_annual Instrução SQL Para testar o exemplo 1: Escreva o código utilizando um editor de textos; salve o arquivo com a extensão “.sql” (p.expl.: e-xemplo1.sql); no prompt do Sql*Plus digite: @localização do arquivo\nome do arquivo, por exem-plo:

SQL>@C:\programas\exemplo1.sql

No exemplo 1 foi utilizado o comando PRINT para exibição do resultado do processamento. Uma outra opção para isso é a utilização do pacote DBMS_output e procedimento put_line. Sintaxe:

DBMS_output.put_line(mensagem);

onde mensagem pode ser: • uma cadeia de caracteres, por exemplo: DBMS_output.put_line (‘O nome do funcionário é’); e

neste caso deverá ser especificada entre apóstrofos. • uma variável ou constante, por exemplo: DBMS_output.put_line (v_sal_anual); • ou ambas, por exemplo: DBMS_output.put_line(nome do funcionário é ’ || v_sal_anual);

utilizando o operador de concatenação || para unir as duas mensagens. ATENÇÃO: Para a utilização deste pacote é necessário ativá-lo no SQL*Plus por meio da instru-ção SET SERVEROUTPUT ON. Exemplo 2: Calcular o salário anual de dado funcionário com base no salário mensal fornecido pe-lo usuário. Exibir o resultado. SET SERVEROUTPUT ON ACCEPT p_nome PROMPT ‘Digite o nome do funcionário...’ ACCEPT p_sal_mes PROMPT ‘Digite o valor do salario...’

Instrução SQL

Declare v_nome varchar2(30) := ‘&p_nome’; v_sal number(9,2) := &p_sal_mes; v_sal_anual number(9,2); Begin v_sal_anual := v_sal * 12; DBMS_output.put_line(‘O salario anual de ‘ || END;

v_nome || ‘ é ‘ || v_sal_anual);

/

Bloco PL/SQL

No exemplo 2 não está sendo utilizada a variável de ligação g_sal_anual, pois a solicitação da exi-bição do resultado do processamento está sendo feita na área executável do bloco PL/SQL.

Page 8: Apostila PLSQL

1.1.6. Instruções SELECT em PL/SQL Recuperar dados do banco de dados com a instrução SELECT. Sintaxe:

SELECT colunas INTO {variáveis...| registro} FROM tabela WHERE condição;

onde, colunas: lista de colunas que retornarão dados à consulta; podem incluir funções de

linhas, de grupo ou expressões SQL Into: cláusula obrigatória, usada para especificar os nomes das variáveis que ar-

mazenarão os valores que o SQL retornará a partir da cláusula SELECT. Deve-se oferecer uma variável para cada coluna, seguindo a mesma ordem.

Variáveis: nome das variávies que irão armazenar o valor recuperado Registro: é o registro PL/SQL para armazenar os valores recuperados Tabela: especifica o nome da tabela do banco de dados Condição: é composta de nomes de coluna, expressões, constantes e operadores de

comparação, incluindo as variáveis PL/SQL e operadores.

Exemplo 3: Recuperar o nome e o cargo do funcionário para o código indicado.

VARIABLE g_nome varchar2(15) VARIABLE g_cargo varchar2(15) DECLARE

v_nome EMP.EMPR_NOME_DS%type; v_cargo EMP.EMPR_SERV_DS%type;

BEGIN select EMPR_NOME_DS, EMPR_SERV_DS into v_nome, v_cargo from EMPR where EMPR_NUME_NR = 7934;

:g_nome := v_nome; END;

:g_cargo := v_cargo;

/ PRINT g_nome PRINT g_cargo

ATENÇÃO: As instruções SELECT em um bloco PL/SQL as consultas devem retornar apenas uma linha, mais de uma ou nenhuma linha geram mensagens de erro que poderá ser tratado. Para consultas que retornam várias linhas deverá ser criado um cursores explícitos, que serão vistos a-diante. Exemplo 4: Calcular e exibir a somatória do salário de todos os funcionários de um dado depar-tamento.

SET SERVEOUTPUT ON DECLARE

v_soma_sal EMPR_SALA_VL%TYPE; v_deptno NUMBER NOT NULL := 10;

BEGIN SELECT SUM(sal) INTO v_soma_sal FROM empr WHERE deptno = v_deptno;

Page 9: Apostila PLSQL

DBMS_output.put_line(‘A soma dos salários do departamento ‘ || v_deptno || ‘ é ‘ || v_soma_sal);

END;

1.1.7. Aninhamento de blocos e Escopo das variáveis As variáveis podem ser utilizadas em determinadas áreas do programa, um bloco PL/SQL pode ser composto por vários blocos aninhados (sub-blocos), cada sub-bloco pode possuir suas variá-veis. No exemplo 5 a variável valor1 é declarada nos 3 sub-blocos que compõe o programa, mas em cada bloco o seu valor é preservado e não é gerado nenhum tipo de conflito pois estas variá-veis são locais. Exemplo 5: Aninhamento de blocos e escopo de variáveis

SET SERVEROUTPUT ON DECLARE -- bloco 1

valor1 number(2) := 7; valor2 number(2) := 13;

BEGIN -- bloco 1 DECLARE -- bloco 2

valor1 varchar2(30) := 'Valor 1 do bloco 2'; BEGIN -- bloco 2

DECLARE -- bloco 3 valor1 date := sysdate;

BEGIN -- bloco 3 DBMS_OUTPUT.PUT_LINE('Valor 1 do bloco 3...' || valor1);

END; -- bloco 3 DBMS_OUTPUT.PUT_LINE('Valor 1 do bloco 2...' || valor1);

END; -- bloco 2 DBMS_OUTPUT.PUT_LINE('Valor 1 do bloco 1... ' || valor1);

END; -- bloco 1 /

Resultado da execução do bloco: SQL> @c:\programas\escopo.sql Valor 1 do bloco 3...12/05/04 Valor 1 do bloco 2...Valor 1 do bloco 2 Valor 1 do bloco 1... 7

1.1.8. Inserção de Dados Exemplo 6: Adicionar informações sobre novos funcionários na tabela EMPR.

DECLARE

v_ename EMPR_NOME_DS%type := 'ZE TONHAO'; v_job EMP.EMPR_SERV_DS%type := 'BALCONISTA'; v_deptno EMPR.DEPT_NUME_NR%type := 30;

BEGIN Insert into EMPR (EMPR_NUME_NR, EMPR_NOME_DS, EMPR_SERV_DS, DEPT_NUME_NR) values (v_empno, v_ename, v_job, v_deptno);

END;

Page 10: Apostila PLSQL

1.1.9. Atualizando Dados Exemplo 7: Aumentar o salário de todos os funcionários na tabela EMPR e que sejam Analistas, adicionando 2000 ao valor do salário.

DECLARE v_sal_increase empr_sala_vl%TYPE := 2000;

BEGIN UPDATE empr SET empr_sala_vl = empr_sala_vl + v_sal_increase WHERE EMPR_SERV_DS = 'ANALISTA';

END;

1.1.10. Exclusão de Dados Exemplo 8: Deletar linhas que pertençam ao departamento 10 da tabela EMPR.

DECLARE v_deptno empr.dept_nume_nr%TYPE := 10;

BEGIN DELETE FROM empr WHERE dept_nume_nr = v_deptno;

END;

1.1.11. Controle de Transações O controle da lógica das transações é realizado com as instruções COMMIT e ROLLBACK, tor-nando permanentes as alterações em alguns grupos de bancos de dados e descartando outros. Assim como ocorre com o Oracle Server, as transações DML são iniciadas no primeiro comando seguindo uma instrução COMMIT ou ROLLBACK e são finalizadas na próxima instrução COMMIT ou ROLLBACK correta. Essas ações podem ocorrer em um bloco PL/SQL ou como resultado dos eventos no ambiente do host (por exemplo, o encerramento de uma sessão SQL*Plus automati-camente compromete a transação pendente). 1.2. Estruturas de Controle As estruturas de controle permitem estabelecer o fluxo lógico de instruções que serão executadas. Para isso podem ser utilizadas as estruturas de controle para repetição de blocos do programa (loop) e as estruturas de controle para avaliação de condições e seleção (if).

1.2.1. Estruturas de seleção As estruturas de seleção possibilitam que o fluxo de processamento das instruções PL/SQL seja direcionado de acordo com a condição especificada. Existem três maneiras para se utilizar a ins-trução If: IF (condição) THEN Conjunto de instruções ; END IF;

Neste caso, se o teste de avaliação da condição retornar verdadeiro o conjunto de instruções será realizado, caso contrário o bloco de seleção é encerrado.

IF(condição) THEN Conjunto de instruções 1; ELSE Conjunto de instruções 2; END IF;

Neste caso, se o teste de avaliação da condição retornar verdadeiro o conjunto de instruções 1 será realizado, caso contrário o será realizado o conjunto de instruções 2.

Page 11: Apostila PLSQL

IF (condição1 ) THEN Conjunto de instruções 1; ELSIF (condição 2) Conjunto de instruções 2 ; ... ELSE Conjunto de instruções n; END IF;

Neste caso, se o teste de avaliação da condição retornar verdadeiro, o conjunto de instruções 1 será realizado, senão, será realizado o teste de avaliação da condição 2. Se o resultado for verdadeiro será realizado o conjunto de instruções 2, senão, será realizado o teste avaliação da condição 3, e assim por diante. Caso nenhuma das condições testadas resultar verdadeiro será realizado o conjunto de instruções previsto após o ELSE.

onde, condição é uma expressão ou variável Booleana (TRUE, FALSE ou NULL) (Ela está asso-

ciada a uma seqüência de instruções, que será executada somente se a expres-são produzir TRUE.)

THEN é uma cláusula que associa a expressão Booleana que a precede com a seqüên-cia de instruções posterior

instruções pode ser uma ou mais instruções SQL ou PL/SQL. (Elas podem incluir mais ins-truções IF contendo diversos IFs, ELSEs e ELSIFs aninhados.)

ELSIF é uma palavra-chave que introduz uma expressão Booleana. (Se a primeira con-dição produzir FALSE ou NULL, a palavra-chave ELSIF introduzirá condições adi-cionais.)

ELSE é uma palavra-chave que se for atingida pelo controle, executará a seqüência de instruções que segue a palavra-chave

Exemplo 9: Definir o ID do gerente como 22 se o nome do funcionário for OSBORNE

... IF v_ename = 'OSBORNE' THEN

vEND IF;

_mgr := 22;

... Exemplo 10: Definir o cargo como Salesman, o número do departamento como 35 e a comissao com o valor de 20% do salário atual se o nome for MILLER.

... IF v_ename = ‘MILLER’ THEN

v_job := ‘SALESMAN’; v_deptno := 35; v_valor_com := sal * 0,20;

END IF; ...

Exemplo 11: Definir o cargo para Manager se o nome do funcionário for King. Se o nome do fun-cionário for diferente de King, defina o cargo para Clerk.

... IF v_ename = ‘KING’ THEN

v_job := ‘MANAGER’; ELSE

v_job := ‘CLERK’; END IF; ...

Exemplo 12: Dado um valor qualquer, representado pela variável v_valor, calcule um percentual deste valor, de acordo com as condições estabelecidas, e armazene em v_perc_valor.

Page 12: Apostila PLSQL

Se o valor for maior do que 100, 100% Se o valor for maior do que 50 e menor ou igual a 100, 50% Para os demais valores 10%

... IF v_valor > 100 THEN

v_perc_valor := 2 * v_start; ELSIF v_valor >= 50 THEN

v_perc_valor := .5 * v_start; ELSE

v_perc_valor := .1 * v_start; END IF; ...

ATENÇÃO: É permitida qualquer quantidade de cláusulas ELSIF, mas pode haver no máximo uma cláusula ELSE. 1.2.2. Estruturas de repetição (Loop) Em determinadas situações temos que repetir o programa ou parte dele inúmeras vezes. Reiniciar o programa para cada repetição não é uma solução muito prática, e algumas vezes é inviável. Uma solução comum é a utilização de estruturas de repetição. Segundo Puga i o conceito de repetição (ou looping) é utilizado quando se deseja repetir certo tre-cho de instruções por um número de vezes. O número de repetições pode ser conhecido anterior-mente ou não, mas necessariamente precisa ser finito. Nem todas as estruturas de repetição possuem recursos para fazer a contagem do número de ve-zes que o laço deverá ser repetido, por isso, deve-se utilizar uma variável de apoio sempre do tipo inteiro. O PL/SQL oferece diversos recursos para estruturar laços de repetição:

• Loop básico para fornecer ações repetitivas sem condições gerais • Loops FOR para fornecer controle iterativo para ações com base em uma contagem • Loops WHILE para fornecer controle iterativo para ações com base em uma condição

ATENÇÃO: Instrução EXIT para termina o laço de repetição

1.2.2.1 Loop Básico Um loop básico permite a execução de sua instrução pelo menos uma vez, entretanto, se a condi-ção exit for colocada no início do loop, antes de qualquer outra instrução executável, e ela for ver-dadeira, ocorrerá a saída do loop e as instruções jamais serão executadas. Sem a instrução EXIT, o loop seria infinito! Sintaxe: LOOP delimitador de início do laço conjunto de instruções; instruções a serem executadas em cada iteração EXIT [WHEN condição]; condição para saída do laço END LOOP; delimitador de fim do laço

Pode-se emitir EXIT como uma ação dentro de uma instrução IF ou como uma instrução indepen-dente dentro do loop. Quando a instrução EXIT é encontrada, a condição na cláusula WHEN é a-valiada, se a condição produzir TRUE, o loop finalizará e o controle passará para a próxima instru-ção após o loop. Um loop básico pode conter várias instruções EXIT..

Page 13: Apostila PLSQL

Exemplo 13: Inserir os 10 primeiros novos itens de linha para o número do pedido 601.

DECLARE v_ordid item.ordid%TYPE := 601; v

BEGIN _counter NUMBER(2) := 1;

LOOP INSERT INTO item (ordid, itemid) VALUES (v_ordid, v_counter); v_counter := v_counter + 1;

EXIT WHEN v_counter > 10; END LOOP;

END;

1.2.2.2 Loop FOR Os loops FOR, realizam as iterações de acordo com a instrução de controle que precede a pala-vra-chave LOOP. Sintaxe: FOR contador in [REVERSE] limite_inferior..limite_superior LOOP conjunto de instruções; . . . END LOOP; onde, Contador é um inteiro declarado implicitamente cujo valor aumenta ou diminui automati-

camente (diminuirá se a palavra-chave REVERSE for usada) em 1 a cada ite-ração do loop até o limite superior ou inferior a ser alcançado

REVERSE faz o contador decrescer a cada iteração a partir do limite superior até o imite inferior. (Note que o limite inferior ainda é referenciado primeiro.)

limite_inferior especifica o limite inferior da faixa de valores do contador limite_superior especifica o limite superior da faixa de valores do contador ATENÇÃO: A seqüência de instruções é executada sempre que o contador é incrementado, con-forme determinado pelos dois limites. Os limites superiores e inferiores da faixa do loop podem ser literais, variáveis ou expressões, mas devem ser avaliados para inteiros. Se o limite inferior da fai-xa do loop for avaliado para um inteiro maior do que o limite superior, a seqüência de instruções não será executada. Exemplo 14: Inserir os 10 primeiros novos itens de linha para o número do pedido 601.

DECLARE v_ordid item.ordid%TYPE := 601;

BEGIN FOR i IN 1..10 LOOP

INSERT INTO item(ordid, itemid) VALUES(v_ordid, i);

END LOOP; END;

1.2.2.3 Loop WHILE Pode-se usar o loop WHILE para repetir uma seqüência de instruções até que a condição para controle não seja mais verdadeira, a condição é avaliada ao início de cada iteração, sendo assim, se a condição for falsa no início do loop, nenhuma iteração futura será executada.

Page 14: Apostila PLSQL

Sintaxe: WHILE condição LOOP conjunto de instruções; . . . END LOOP; Onde, condição é uma expressão ou variável Booleana (TRUE, FALSE, ou NULL) instrução pode ser uma ou mais instruções SQL ou PL/SQL ATENÇÃO:

• Se as variáveis envolvidas nas condições não se alterarem no curso do corpo do loop, a condição permanecerá TRUE e o loop não terminará.

• Se a condição produzir NULL, o loop será ignorado e o controle passará para a próxima

instrução. Exemplo 15: Solicitar o número de iterações do laço e exibir o valor da variável de controle a cada iteração.

ACCEPT p_no_voltas PROMPT 'Digitar o número de voltas do laço: ' DECLARE

vBEGIN

_count NUMBER(2) := 1;

WHILE v_count <= &p_no_voltas LOOP DBMS_OUTPUT.PUT_LINE(‘Valor do contador...’ || v_count); v_count := v_count + 1;

END LOOP; END; /

1.2.3. Loops e Labels Aninhados Pode-se aninhar loops para vários níveis. Você pode aninhar loops básicos, FOR e WHILE um dentro do outro. A terminação de um loop aninhado não terminará o loop delimitado a menos que seja criada uma exceção. Entretanto, pode-se colocar labels em loops e sair do loop externo com a instrução EXIT. Os nomes de labels seguem as mesmas regras de outros identificadores. Um label é colocado an-tes de uma instrução, seja na mesma linha ou em uma linha separada. Colocar o label no loop an-tes da palavra LOOP dentro dos delimitadores de label (<<label>>). Se for atribuído um label ao loop, o nome do label poderá ser opcionalmente incluído após a ins-trução END LOOP para clareza. No exemplo a seguir, existem dois loops. O loop externo é identificado pelo label, <<Loop_externo>> e o loop interno é identificado pelo la-bel <<Loop_interno>>. O loop interno está aninhado dentro do Loop externo. Os nomes de label são incluídos após a instrução END LOOP para clareza. Exemplo 16: Demonstração do uso de labels.

... BEGIN

<<looLOOP

p_externo>>

v_counter := v_counter+1; EXIT WHEN v_counter>10; <<loop_interno>> LOOP

...

Page 15: Apostila PLSQL

EXIT Outer_loop WHEN total_done = 'YES'; -- Abandona ambos os Loops EXIT WHEN inner_done = 'YES'; -- Abandona somente o Loop interno

... END LOOP loop_interno;

... END LOOP loop_externo;

END; . . .

1.3. Cursores Para processar uma instrução de SQL o Oracle atribui uma área de memória denominada área de contexto. A área de contexto contém o número de linhas processadas, um apontador e, para con-sultas, o conjunto ativo. O conjunto ativo é o conjunto de linhas recuperadas uma consulta, por e-xemplo:

• A consulta select * from EMPR terá como conjunto ativo todas as linhas e colunas da tabela

EMPR; • Na consulta select EMPR_NOME_DS, EMPR_SERV_DS from EMPR where

DEPT_NUME_NR = 20, o conjunto ativo será composto pelas linhas e colunas que atendem à condição.

• O cursor é o apontador da área de contexto. Existem dois tipos de cursores os cursores: • Implícitos: não é declarado e é realizado implicitamente quando as instruções DML e PL/SQL

select ..into são realizadas. Processam apenas uma linha. Se uma consulta retornar mais do que uma linha um erro será gerado.

• Explícitos: precisam ser declarados explicitamente na área declarativa do bloco PL/SQL. Po-de processar várias linhas; por meio de um cursor explícito é possível, em um bloco PL/SQL, controlar a área de contexto e os processamentos que nela ocorrem

ATENÇÃO: Todos os exemplos de blocos PL/SQL, apresentados até este ponto e que continham instruções DML são exemplos de cursores implícitos. Os atributos de cursores podem ser utilizados em cursores implícitos ou explícitos. Estes atributos permitem a realização de testes nos resultados das instruções SQL, são eles: • %FOUND: retorna verdadeiro caso alguma linha (tupla) tenha sido afetada • %NOTFOUND: retorna verdadeiro caso não tenha encontrado nenhuma tupla. Seu valor é fal-

so até a última tupla. • %ISOPEN: indica se o cursor está aberto ou não. • %ROWCOUNT: retorna o número de tuplas do cursor. Exemplo 17: Deletar linhas que especificaram um número de ordem de compra a partir da tabela ITEM. Exibir o número de linhas deletadas.

VARIABLE linhas_deletadas VARCHAR2(30) DECLARE

vBEGIN

_deptno NUMBER := 10;

DELETE FROM EMPR WHERE DEPT_NUME_NR = v_deptno; :linhas_deletadas := (SQL%ROWCOUNT || ' linhas deletadas.');

END; /

Page 16: Apostila PLSQL

PRINT linhas_deletadas O exemplo 17 é um cursor implícito, o atributo SQL%ROWCOUNT está sendo utilizado para pos-sibilitar a exibição do número de linhas deletadas.

1.3.1. Cursores Explícitos O Oracle Server usa áreas de trabalho chamadas áreas SQL particulares para executar instruções SQL e para armazenar informações de processamento. Pode-se usar cursores do PL/SQL para nomear uma área SQL particular e acessar suas informações armazenadas. Os cursores explícitos podem ser utilizados para processar individualmente cada linha retornada por uma instrução SE-LECT de várias linhas. O cursor orienta todas as fases do processamento. Conjunto Ativo Linha atual

7369 SMITH CLERK

7566 JONES MANAGER

7788 SCOTT ANALYST

7876 ADAMS CLERK

7902 FORD ANALYST

cursor

O conjunto de linhas retornado por uma consulta de várias linhas é chamado conjunto ativo. Seu tamanho é correspondente ao número de linhas que atende aos critérios da pesquisa. A figura an-terior mostra como um cursor explícito "aponta" para a linha atual do conjunto ativo. Isso permite que o programa processe as linhas uma de cada vez. Um programa PL/SQL abre um cursor, processa linhas retornadas por uma consulta e, em segui-da, fecha o cursor. O cursor marca a posição atual no conjunto ativo. A seqüência para execução do controle dos cursores consiste em:

Declaração

Abertura

Recuperação das

Linhas →

Verificação do

término

Fechamento

1. Declare o cursor nomeando-o e definindo a estrutura da consulta a ser executada dentro

dele. 2. Abra o cursor. A instrução OPEN executa a consulta e vincula as variáveis que estiverem

referenciadas. As linhas identificadas pela consulta são chamadas conjunto ativo e estão agora disponíveis para extração.

3. Extraia dados do cursor. No diagrama de fluxo mostrado no slide, após cada extração você testa o cursor para qualquer linha existente. Se não existirem mais linhas para serem pro-cessadas, você precisará fechar o cursor.

4. Feche o cursor. A instrução CLOSE libera o conjunto ativo de linhas. Agora é possível rea-brir o cursor e estabelecer um novo conjunto ativo.

1.3.1.1 Declaração de cursores explícitos Os cursores explícitos devem ser declarados no bloco PL/SQL e a manipulação do seu conjunto ativo deve ser realizada na área de processamento do bloco. Sintaxe:

CURSOR nome_cursor IS consulta;

Onde,

CURSOR é a instrução utilizada para declarar um cursor explícito.

Page 17: Apostila PLSQL

nome_cursor é um identificador para o cursor consulta é uma instrução SELECT

ATENÇÃO: • Não se deve incluir a cláusula INTO na declaração de cursor porque ela aparecerá posteri-

ormente na instrução FETCH. • Pode-se fazer referência a variáveis dentro da consulta, mas elas devem ser declaradas

antes da instrução CURSOR. Exemplo 18: Declarar cursores para recuperar o código e o nome de todos os funcionários e para recuperar todas as colunas da tabela dept quando o código do departamento for igual a 10.

DECLARE CURSOR EMPR_cursor IS SELECT EMPRno, EMPR_NOME_DS FROM EMPR; CURSOR dept_cursor IS SELECT * FROM dept WHERE deptno = 10; BEGIN ...

1.3.1.2 Abertura do Cursor A instrução OPEN abre o cursor para executar a consulta e identificar o conjunto ativo, que consis-te em todas as linhas que atendem aos critérios de pesquisa da consulta. O cursor aponta agora para a primeira linha do conjunto ativo. Sintaxe:

OPEN nome_cursor; OPEN é uma instrução executável que realiza as seguintes operações:

1) Aloca memória dinamicamente para uma área de contexto que finalmente conterá in-formações cruciais de processamento.

2) Analisa a instrução SELECT. 3) Vincula as variáveis de entrada — isto é, define o valor das variáveis de entrada obten-

do seus endereços de memória. 4) Identifica o conjunto ativo — isto é, o conjunto de linhas que satisfaz os critérios de

pesquisa. As linhas no conjunto ativo não são recuperadas para variáveis quando a ins-trução OPEN é executada. Em vez disso, a instrução FETCH recupera as linhas.

5) Posiciona o indicador imediatamente antes da primeira linha no conjunto ativo.

ATENÇÃO: Se a consulta não retornar qualquer linha quando o cursor for aberto, o PL/SQL não criará uma exceção , pode-se testar o status do cursor após a extração. 1.3.1.3 Recuperação das linhas do Cursor A instrução FETCH recupera as linhas no conjunto ativo uma de cada vez. Após cada extração, o cursor avança para a próxima linha no conjunto ativo. Sintaxe: FETCH cursor_name INTO [variável1, variável2, ...|record_name];

Page 18: Apostila PLSQL

onde, cursor_name é o nome do cursor declarado anteriormente variável é uma variável de saída para armazenar os resultados, o número de

variáveis deve ser compatível com o número de colunas da consulta. record_name é o nome do registro em que os dados recuperados são armazenados (A

variável de registro pode ser declarada usando o atributo %ROWTY-PE.)

A instrução FETCH realiza as seguintes operações:

1) Avança o indicador para a próxima linha no conjunto ativo.

2) Lê os dados da linha atual para as variáveis PL/SQL de saída. Deve-se incluir o mesmo número de variáveis na cláusula INTO da instrução FETCH do que as co-lunas na instrução SELECT, as variáveis devem ser do mesmo tipo de dado da coluna correspon-dente. Como alternativa, pode ser definido um registro para o cursor e faça referência do registro na cláusula FETCH INTO. Verificar se o cursor possui linhas. Se uma extração não obtiver valores, não existem linhas rema-nescentes para serem processadas no conjunto ativo e nenhum erro será registrado.

1.3.1.4 Fechamento de Cursor A instrução CLOSE desativa o cursor e o conjunto ativo se torna indefinido. O cursor deve ser fe-chado após completar o processamento da instrução SELECT. Essa etapa permite que o cursor seja reaberto, se necessário. Assim, pode-se estabelecer um conjunto ativo diversas vezes; A á-rea de contexto é liberada. Sintaxe:

CLOSE nome_cursor; Embora seja possível terminar o bloco PL/SQL sem fechar cursores, deve-se criar o hábito de fe-char qualquer cursor declarado explicitamente para liberar recursos. Existe um limite máximo para o número de cursores abertos por usuário, que é determinado pelo parâmetro OPEN_CURSORS no campo de parâmetros do banco de dados. OPEN_CURSORS = 50 por default. Exemplo 19: Criar um bloco PL/SQL no qual seja calculado o salário anual de cada funcionário e armazene na tabela sal_tot o nome do funcionário e o seu salário anual. 1 ACCEPT p_cargo_func PROMPT 'Digite o CARGO do funcionário ' 2 VARIABLE g_n_ocorrencias NUMBER; 3 DECLARE 4 v_cargo_func EMPR_SERV_DS%TYPE := '&p_cargo_func'; 5 v_nome_func EMPR_NOME_DS%TYPE; 6 v_sal_mes EMPR_SALA_VL%TYPE; 7 v_sal_ano number(9,2); 8 CURSOR sal_func_cursor IS 9 SELECT EMPR_NOME_DS, EMPR_SALA_VL, EMPR_SALA_VL * 12 10 FROM EMPR 11 WHERE EMPR_SERV_DS = v_cargo_func; 12 BEGIN 13 OPEN sal_func_cursor; 14 LOOP 15 FETCH sal_func_cursor INTO v_nome_func, v_sal_mes, v_sal_ano; 16 EXIT WHEN sal_func_cursor%NOTFOUND; 17 INSERT INTO sal_tot VALUES(v_nome_func, v_sal_ano); 18 END LOOP;

Page 19: Apostila PLSQL

19 :g_n_ocorrencias := sal_func_cursor%ROWCOUNT; 20 CLOSE sal_func_cursor; 21 END; 22 / 23 PRINT g_n_ocorrencias Sobre o exemplo: As linhas do exemplo 19 foram enumeradas para facilitar a explicação sobre o código. Na linha 8 está sendo iniciada a declaração do cursor sal_func_cursor, observe que na linha 11, na condição para recuperação das linhas do cursor, é utilizada a variável v_cargo_func que foi decla-rada anteriormente na linha 4. Na linha 13 o cursor é aberto. Na linha 14 é iniciado o laço de repetição que será encerrado quando não existirem mais linhas no conjunto ativo para serem percorridas (linha 16) Na linha 15 a instrução fetch recupera a linha corrente do conjunto ativo e armazena os dados das colunas nas variáveis v_nome_func, v_sal_mes, v_sal_ano Na linha 17 os valores recuperados são inseridos na tabela sal_tot. Na linha 20 o cursor é fechado.

1.3.2. Cursores de Atualização Os registros retornados pela consulta que está associada a um cursor podem ser lidos, alterados ou excluídos. Os cursores que permitem este tipo de operação são chamados cursores de atuali-zação e devem ser declarados da seguinte maneira: cursor nome_cursor is select ... from ... (consulta) for update [of nome_coluna] [nowait]; Veja o exemplo de um cursor para atualização e a seguir as explicações do código e das cláusulas da sintaxe: 1 Declare 2 cursor cursor_ex_atual 3 Is 4 select EMPR_NOME_DS, EMPR_SERV_DS, sal 5 from EMPR 6 for update of sal nowait; 7 Begin 8 for reg_ex_atual in cursor_ex_atual loop 9 if reg_ex_atual.job = ‘CLERK’ then 10 update EMPR set sal = sal * 1.10 11 where current of cursor_ex_atual; 12 elseif reg_ex_atual.job = ‘PRESIDENT’ then 13 update EMPR set sal = sal + sal 14 where current of cursor_ex_atual; 15 Else 16 delete from EMPR 17 where current of cursor_ex_atual; 18 end loop;

Sobre o código:

• A cláusula for update, utilizada na linha 6, deve ser a última instrução da declaração de um cursor e indica que os registros retornados pelo cursor poderão ser atualizados (alterados ou excluídos)

Page 20: Apostila PLSQL

• of sal, linha 6, indica a coluna ou lista de colunas de referência para consulta, neste caso sal é a coluna que será atualizada. Está expressão é opcional.

• A cláusula nowait, linha 6, deve ser utilizada para gerar uma exceção tratável caso a tabela esteja bloqueada por outro usuário, isto é, será emitida uma mensagem informando que a tabela a ser utilizada está bloqueada por outro usuário. Está cláusula é opcional, no entan-to, se for omitida o cursor de atualização ficará por tempo indeterminado esperando o des-bloqueio da tabela para que prossiga com a consulta.

• A variável reg_ex_atual, é declarada implicitamente como cursor_ex_atual%rowtype, (na li-nha 8), isto é, está variável é do tipo registro e possui os mesmos campos utilizados na consulta associada ao cursor. Isso ocorre toda vez que a instrução for é utilizada para con-trolar a leitura dos registros retornados pela consulta em questão.

• Para referenciar um campo deve-se colocar o nome da variável . (ponto) e o nome do cam-po, por exemplo: reg_ex_atual.job está sendo referenciado o campo EMPR_SERV_DS da tabela EMPR.

• A instrução where current of nome_cursor, linhas 11, 14 e 17, indica que a operação de atualização ou exclusão será realizada no registro corrente, isto é, no registro que está sendo apontado pelo cursor naquele momento.

1.3.3. Variáveis de Cursores Os cursores vistos até então, são estáticos, isto é, o cursor é associado a uma instrução SQL que em tempo de compilação retorna os registros associados àquela consulta. As variáveis de cursor podem ser utilizadas para receber valores em tempo de execução possibilitando que diferentes re-sultados sejam obtidos a partir de um único cursor. As variáveis de cursor são do tipo referência e devem ser declarados da seguinte maneira: TYPE nome_tipo IS REF CURSOR RETURN tipo_retorno; onde,

nome_tipo é o nome do tipo de referência o tipo de retorno tem que ser do tipo registro Variáveis do tipo referência (REF) são como apontadores, isto é, apontam para diferentes áreas de memória ao longo da utilização do programa, são diferentes das variáveis comuns que são utili-zadas para identificar uma área de memória. Variáveis do tipo registro podem ser declaradas utilizando %ROWTYPE Exemplos de declarações de variáveis de cursor: Exemplo 1

TYPE t_registro IS RECORD ( nome EMP.EMPR_NOME_DS%type, cargo EMPR_SERV_DS%type); v_registro t_registro; TYPE t_referencia IS REF CURSOR RETURN t_registro;

sobre o exemplo:

• está sendo declarada o tipo t_registro, do tipo registro. Este registro será composto pelos campos nome e cargo que possuem respectivamente o formato do campo EM-PR_NOME_DS da tabela EMPR e EMPR_SERV_DS da mesma tabela.

• está sendo declarada a variável v_registro que será do tipo t_registro, tipo construido na declaração anterior

• está sendo declarado o tipo referência t_referencia para o cursor, que terá como retorno o valor de t_registro.

Exemplo 2- usando %ROWTYPE:

TYPE t_AlunoRef IS REF CURSOR RETURN aluno%ROWTYPE;

Page 21: Apostila PLSQL

Para abrir uma variável de cursor para consulta

OPEN variável_cursor FOR consulta_pretendida Exemplo:

DECLARE TYPE t_AlunoRef IS REF CURSOR RETURN aluno%ROWTYPE; v_aluno t_alunoRef; ... BEGIN ...

OPEN v_aluno FOR SELECT nome, curso from ALUNO; ...

ATENÇÃO: O retorno do cursor deve ser compatível com o retorno da consulta, caso contrário o-correrá um erro. 1.4. Tratamento de Exceções Uma exceção é uma ocorrência não esperada, ou diferente daquela programada para ser execu-tada. Em outras palavras uma exceção é um erro! Por exemplo: O usuário digita um caractere para uma variável do tipo numérico, neste exemplo temos uma en-trada de dados diferente da esperada; um cursor declarado com um retorno que espera um conjunto de campos diferentes daqueles que são solicitados pela consulta; Os erros podem ocorrer durante a compilação ou durante a execução do programa. Os erros de compilação estão associados a sintaxe das instruções: nome dos comandos, declaração das vari-áveis, organização dos comandos, entre outros. Neste tipo de erro o compilador da linguagem in-forma ao programador durante a tentativa de executar uma instrução a ocorrência do erro: Exemplo: SQL> selet * from EMPR; SP2-0734: início de comando desconhecido "selet * fr..." - restante da linha ignorado. Os erros de execução (runtime) estão associados à utilização do programa, neste caso quando as exceções não são previstas e tratadas, o erro gerado por elas interrompe o processamento e uma mensagem é devolvida para a aplicação. Exemplo: Ao executar o programa zero.sql, será gerado um erro pela tentativa de dividir um va-lor por zero

declare x number := 0; y number := 5; resultado number; begin resultado := y / x; ... end;

Compilando o programa:

SQL> @zero.sql declare *

Page 22: Apostila PLSQL

ERRO na linha 1: ORA-01476: o divisor é igual a zero ORA-06512: em line 6

Para realização da operação aritmética de divisão, o divisor deverá ser diferente de 0. Não existe erro de sintaxe, mas, o valor esperado para divisor não está adequado, fazendo com que o pro-grama não funcione, então, temos uma exceção! Para resolver este problema algumas linguagens de programação oferecem recursos para trata-mento de exceções. O tratamento de uma exceção consiste em identificar um erro em tempo de execução e tratá-lo de maneira que o usuário seja informado sobre o que está acontecendo e o programa não seja interrompido bruscamente. O Oracle possui alguma exceções pré-definidas, mas o desenvolvedor também pode definir exce-ções personalizadas. O bloco PL/SQL com tratamento de exceções tem a seguinte estrutura:

DECLARE nome_exceção exception; /* declaração da exceção BEGIN RAISE exceção; /* abertura da exceção EXCEPTION /* área de tratamento das exceções WHEN nome_exceção THEN instruções para tratamento da exceção; WHEN OTHERS THEN instruções para tratamento da exceção; END;

1.4.1. Exceções pré-definidas nomeadas Para alguns erros comuns, existem pré-definições de exceções, não havendo, neste caso, a ne-cessidade de serem declaradas para serem utilizadas. Exemplo 1: 1 ACCEPT p_nome PROMPT ‘Digite o nome do funcionário ...’ 2 DECLARE 3 v_nome EMP.EMPR_NOME_DS%type := ‘&p_nome’; 4 BEGIN 5 SELECT EMPR_NOME_DS, sal 6 FROM EMPR 7 WHERE EMPR_SERV_DS = 'CLERK' and EMPR_NOME_DS = v_nome; 8 EXCEPTION 9 when NO_DATA_FOUND then 10 DBMS_OUTPUT.PUT_LINE('Nenhum registro foi encontrado'); 11 when TOO_MANY_ROWS then 12 DBMS_OUTPUT.PUT_LINE('Muitos funcionários possuem este cargo'); 13 when OTHERS then 14 DBMS_OUTPUT.PUT_LINE('ERRO DESCONHECIDO ' ); 15 END;

Neste exemplo, está sendo realizada uma consulta (linha 5), como esta consulta não está associada a um cursor explícito, deverá retornar apenas um registro, caso contrário uma exceção será gerada, isto ocorre pois não está sendo reservada uma área para armazenamento destas in-formações e nem tampouco os dados retornados estão associados à variáveis ou existe uma es-trutura de repetição. Se nenhuma linha for retornada também será gerada uma exceção. Estas du-as exceções são pré definidas pelo Oracle como NO_DATA_FOUND (linha 9) e TO-O_MANY_ROWS (linha 11).

Page 23: Apostila PLSQL

A seção de tratamento de exceção captura somente as exceções especificadas; quaisquer outras exceções não serão capturadas exceto se for utilizado o handler de exceção OTHERS. Es-se handler captura qualquer exceção que ainda não esteja tratada. Por essa razão, OTHERS é o último handler de exceção definido.

No exemplo, na cláusula OTHERS (linha 13), se ocorrer qualquer outra exceção, diferente de NO_DATA_FOUND e TOO_MANY_ROWS será exibida a mensagem 'ERRO DESCONHECI-DO '. ATENÇÃO: Podem ser definidos vários handlers de exceção para o bloco, cada um deles com o seu próprio conjunto de ações. Quando ocorre uma exceção, o código PL/SQL processa somente um handler antes de sair do bloco. As exceções não podem aparecer em instruções de atribuição ou instruções SQL. Funções para Captura de Erro Quando ocorre uma exceção, pode-se identificar o código ou a mensagem de erro associado u-sando duas funções SQLCODE e SQLERRM. Com base nos valores do código ou mensagem, vo-cê pode decidir qual ação subseqüente tomar com base no erro. • SQLERRM – Função numérica que devolve o código do erro; • SQLCODE – Função caractere que devolve o texto da mensagem do erro. Quando uma exceção é capturada no handler de exceção WHEN OTHERS, pode-se usar um con-junto de funções genéricas para identificar esses erros. No exemplo a seguir os valores de SQLCODE e SQLERRM estão sendo atribuídos a variáveis e, em seguida, essas variáveis sendo usadas em uma instrução SQL. Exemplo: 1 DECLARE 2 v_error_code NUMBER; 3 v_error_message VARCHAR2(255); 4 BEGIN 5 ... 6 EXCEPTION 7 ... 8 WHEN OTHERS THEN 9 ROLLBACK; 10 v_error_code := SQLCODE ; 11 v_error_message := SQLERRM ; 12 INSERT INTO errors 13 VALUES(v_error_code, v_error_message); 14 END; ATENÇÃO: Trunque o valor de SQLERRM para um tamanho conhecido antes de tentar gravá-lo para uma variável. 1.4.2. Exceções nomeadas pelo desenvolvedor e associadas a códigos de erro : Devem ser declaradas explicitamente na seção de declarações e abertas na área de processa-mento quanto houver a possibilidade de erro: Exemplo:

set verify on accept p_deptno prompt ' insira o numero do departamento ' accept p_local prompt ' insira a localizaçao do depto ' DECLARE e_depto_invalido EXCEPTION;

Page 24: Apostila PLSQL

v_deptno dept.deptno%type := &p_deptno; BEGIN Update dept set loc = '&p_local'

0 where deptno = v_deptno; 1 IF sql%notfound then 2 Raise e_depto_invalido; 3 end if; 4 commit; 5 EXCEPTION 6 when e_depto_invalido then 7 dbms_output.put_line('departamento ' || to_char(v_deptno) || ' nao

cadastrado'); 8 END;

onde:

• e_depto_invalido EXCEPTION; - (linha 5) está sendo declarada a exceção e_depto_invalido

• caso a instrução para atualização da tabela não encontre registros para efetuar a transa-

ção, bloco de seleção IF (linha 11) abre a exceção e_depto inválido então o fluxo do pro-grama é desviado para a área de tratamento de exceções.

Algumas exceções declaradas pelo usuário podem ser associadas a erros Oracle pré-definidos, mas não nomeados. Podemos associar estas exceções a um nome da seguinte maneira:

PRAGMA EXCEPTION_INIT (nome_exceção, código_Oracle_erro); onde,

nome_exceção – deve ser declarada na área declarativa codigo_Oracle_erro – deve-se associar a exceção declarada ao número de erro padrão

Na área de exceções deve-se fazer referência à exceção declarada dentro da rotina de tratamento de exceção correspondente. O PRAGMA EXCEPTION_INIT é uma diretiva de compilação que informa o compilador para as-sociar um nome de exceção a um número de erro do Oracle. Isso permite que possa ser consulta-da qualquer exceção interna por nome e criado um handler específico para ela. ATENÇÃO: PRAGMA (também chamado pseudo-instruções) é uma palavra-chave que signi-fica que a instrução é uma diretiva de compilador, que não é processada ao executar o blo-co PL/SQL. Ao invés disso, orienta o compilador do PL/SQL para interpretar todas as ocor-rências do nome da exceção dentro do bloco como o número de erro do Oracle Server as-sociado. Exemplo: Capturar por número de erro do Oracle Server –2292, uma violação de restrição de in-tegridade. Se um determinado usuário tentar remover um departamento, para o qual existam fun-cionários, imprima uma mensagem informando que esse departamento não pode ser removido. 1 DECLARE 2 e_emps_remaining EXCEPTION; 3 PRAGMA EXCEPTION_INIT ( e_emps_remaining, -2292); 4 v_deptno dept.deptno%TYPE := &p_deptno; 5 BEGIN 6 DELETE FROM dept 7 WHERE deptno = v_deptno; 8 COMMIT; 9 EXCEPTION

Page 25: Apostila PLSQL

10 WHEN e_emps_remaining THEN 11 DBMS_OUTPUT.PUT_LINE (‘Não é possível remover o departamento’ ||

TO_CHAR(v_deptno) || '. Existem funcionários. '); 12 END; Na linha 2 está sendo declarada a exceção e_emps_remaining. Na linha 3 a exceção declarada está sendo associada ao erro oracle –2292. Exceções declaradas e definidas pelo desenvolvedor O PL/SQL permite que você defina suas próprias exceções. As exceções PL/SQL definidas pelo usuário devem ser: Declaradas na seção de declaração de um bloco PL/SQL Criadas explicitamente com instruções RAISE Exemplo: Esse bloco atualiza a descrição de um produto. O usuário fornece o número do produto e a nova descrição. Se o usuário incluir um número de produto inexistente, nenhuma linha será a-tualizada na tabela PRODUCT. Crie uma exceção e imprima uma mensagem para o usuário aler-tando-os de que foi incluído um número de produto inválido. 1 DECLARE 2 e_invalid_product EXCEPTION; 3 BEGIN 4 UPDATE product 5 SET descrip = '&product_description' 6 WHERE prodid = &product_number; 7 IF SQL%NOTFOUND THEN 8 RAISE e_invalid_product; 9 END IF; 10 COMMIT; 11 EXCEPTION 12 WHEN e_invalid_product THEN 13 DBMS_OUTPUT.PUT_LINE('Invalid product number.'); 14 END; Na linha 2 a exceção está sendo declarada; Na linha 8 está sendo criada explicitamente; e Na linha 12 está sendo tratada. Procedimento RAISE_APPLICATION_ERROR O procedimento RAISE_APPLICATION_ERROR é utilizado para comunicar uma exceção predefi-nida interativamente retornando um código ou uma mensagem de erro não padronizada. Com RAISE_APPLICATION_ERROR é possível relatar erros para a aplicação e evitar o retorno de ex-ceções não tratáveis. Sintaxe: RAISE_APPLICATION_ERROR (numero_erro, mensagem[, {TRUE | FALSE}]); Onde: número_erro é um número especificado pelo usuário para a exceção entre –20000 e –20999. mensagem é a mensagem especificada pelo usuário para a exceção. Trata-se de uma string de caracteres com até 2.048 bytes. TRUE | FALSE é um parâmetro Booleano opcional (Se TRUE, o erro será colocado na pilha de erros anteriores. Se FALSE, o default, o erro substituirá todos os erros anteriores.) O procedimento RAISE_APPLICATION_ERROR pode ser usado em dois locais diferentes: – Na seção de exceção

Page 26: Apostila PLSQL

– Na seção executável Exemplo 1 : Utilizando na seção de exceções

... EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR (-20201, 'Manager is not a valid EMPRloyee.'); END;

Exemplo 2 : Utilizando na seção de executável

... BEGIN ... DELETE FROM EMPR WHERE mgr = v_mgr; IF SQL%NOTFOUND THEN RAISE_APPLICATION_ERROR(-20202,'This is not a valid manager'); END IF; ...

Propagando uma Exceção para um Sub-bloco Ao invés de se capturar uma exceção dentro do bloco PL/SQL, é possível propagar a exceção pa-ra permitir que ela seja tratada pelo ambiente de chamada. Cada ambiente de chamada tem seu próprio modo de exibir e acessar erros. Exemplo: DECLARE . . . e_no_rows exception; e_integrity exception; PRAGMA EXCEPTION_INIT (e_integrity, -2292); BEGIN FOR c_record IN EMPR_cursor LOOP BEGIN SELECT ... UPDATE ... IF SQL%NOTFOUND THEN RAISE e_no_rows; END IF; EXCEPTION WHEN e_integrity THEN ... WHEN e_no_rows THEN ... END; END LOOP; EXCEPTION WHEN NO_DATA_FOUND THEN . . . WHEN TOO_MANY_ROWS THEN . . . END;

Quando um sub-bloco trata uma exceção, ele termina normalmente e o controle retorna ao bloco delimitado imediatamente após a instrução END do sub-bloco. Entretanto, se o código PL/SQL criar uma exceção e o bloco atual não tiver um handler para essa exceção, a exceção propagará em blocos delimitados sucessivos até localizar um handler. Se ne-nhum desses blocos tratar a exceção, o resultado será uma exceção não tratável no ambiente de host (chamador).

Page 27: Apostila PLSQL

Quando a exceção propaga para um bloco delimitado, as ações executáveis restantes desse bloco são ignoradas. Uma vantagem desse comportamento é que pode-se delimitar instruções que exigem seus pró-prios tratamentos de erro exclusivos em seu próprio bloco, enquanto deixa o tratamento de exce-ção mais geral para o bloco delimitado. 1.5. Procedimentos

Um procedimento é um conjunto de instruções que realiza determinada tarefa. (Puga[2003]). A de-finição e o funcionamento dos procedimentos é similar à programação em outras linguagens e en-volve basicamente os passos de

• identificação do procedimento • definição dos parâmetros ou parâmetro • conjunto de instruções do procedimento • submissão do código ao SGBDR

Então,

• O código fonte é armazenado no dicionário de dados1 • O procedimento é compilado

o se a compilação for bem sucedida o P-code é armazenado no dicionário de dados e não pode ser consultado

o se ocorrerem erros de compilação, estes serão armazenados no USER_ERRORS Sintaxe: CREATE [ OR REPLACE] nome_procedimento [parâmetro [{in, out, in out}] tipo_parâmetro, ... {IS ou AS}

BEGIN corpo_do_procedimento

END [nome_procedimento];

onde:

Create or replace instrução para criação ou substituição do procedi-mento

nome_procedimento nome que será dado ao procedimento parâmetro [parâmetro [{in, out, in out}]

nome do parâmetro que poderá ser para entrada, sa-ída ou entrada e saída

tipo_parâmetro tipo de dado que o parâmetro poderá aceitar, os pa-râmetros podem ser IN, OUT ou IN OUT

IS ou AS tem a mesma função e indicam o bloco que estará associado ao procedimento, substitui a palavra re-servada DECLARE.

BEGIN corpo_do_procedimento END Respectivamente o início do bloco, o conjunto de ins-truções do procedimento e o final do bloco.

1 Pode-se consultar a USER_SOURCE

Page 28: Apostila PLSQL

1.5.1. Utilizando parâmetros2 de entrada Os parâmetros são por default do tipo IN, isto é, são utilizados para entrada de valores que serão utilizados internamente pelo procedimento.

A procedure reajuste recebe os parâmetros v_código e v_porcentagem cujos valores serão utilizados para alteração de um registro na tabela EMPR.

CREATE OR REPLACE PROCEDURE reajuste (v_codigo_emp IN EMPR_NUME_NR%type, v_porcentagem IN number)

IS

BEGIN

UPDATE EMPR SET sal = sal + (sal *( v_porcentagem / 100 ) ) where EMPRno = v_codigo_emp; COMMIT; END reajuste; /

Os parâmetros IN podem receber valores default: v_porcentagem IN number default 25. ATENÇÃO: Somente os parâmetros IN podem ser atribuídos de valores default, os parâmetros OUT e IN OUT não podem.

1.5.2. Utilizando parâmetros de saída Os parâmetros do tipo OUT são utilizados para saída de valores processados para o ambiente de chamada. A procedure consulta_emp recebe o parâmetro de entrada p_id, que será utilizado na condição da consulta para recuperar o registro de um dado funcionário. O parâmetro de saída p_salário será utilizado para devolver o valor, resultado de uma operação interna da procedure, para a rotina chamadora. (no item 1.1.5 será exemplificada a utilização das procedures)

CREATE OR REPLACE PROCEDURE consulta_emp (p_id in EMPR_NUME_NR%type,

p_nome out EMP.EMPR_NOME_DS%type, p_salario out EMPR.sal%type) BEGIN

IS

select EMPR_NOME_DS, sal into p_nome, p_salario from EMPR where EMPRno = p_id; END consulta_emp; /

2 Parâmetro – um valor, constante ou variável, que é passado de uma rotina chamadora para uma rotina e-xecutora, onde a rotina chamadora é um algoritmo que usa as funcionalidades da rotina executora, por e-xemplo: Parâmetro formal – variáveis da rotina executora que recebem os valores da rotina cha-madora, isto é, recebem os parâmetros reais. ATENÇÃO: As variáveis dos parâmetros formais não devem ter tamanho ou precisão pré determinados. Parâmetro real – valores (constantes ou reais) que são passados da rotina chamadora para a rotina executo-ra.

Page 29: Apostila PLSQL

1.5.3. Utilizando parâmetros de entrada e saída Os parâmetros IN OUT são utilizados para entrada de valores, que poderão ser processados, o parâmetro poderá ser alterado e o seu valor pode ser devolvido para o ambiente de chamada. A procedure formata_fone recebe o parâmetro p_fone, que representa uma cadeia de caracteres. Este parâmetro recebe de o resultado das operações da procedure e devolte este valor a rotina chamadora. Sendo assim é um parâmetro de entrada quando passa para a procedure o valor que será utilizado no processamento, é um parâmetro de saída quando recebe o resultado do processamento, por-tanto, tem o seu valor alterado, e devolve o resultado à rotina chamadora.

CREATE OR REPLACE PROCEDURE formata_fone (p_fone IN OUT varchar2) IS BEGIN P_fone := ‘(‘ || substr(p_fone, 1, 3) || ‘)’ || substr(p_fone, 4, 3) || ‘-’ || substr(p_fone, 7); END formata_fone; /

As instruções para criação do procedimento podem ser digitadas diretamente no prompt do S-QL*Plus ou em um arquivo com extensão sql. Se o código for escrito diretamente no prompt ao te-clar enter após a barra ( / ) será compilado e o procedimento será criado. Uma mensagem informa-rá se o procedimento foi criado com sucesso ou com erros.

Page 30: Apostila PLSQL

1.5.4. Visualização de erros de compilação Quando as compilações não são bem sucedidas a instrução show errors pode ser utilizada para visualizar os erros que ocorreram: Sintaxe:

SQL> show errors resultado:

Erros para PROCEDURE REAJUSTE: LINE/COL ERROR -------- ------------------------------------------- 8/2 PL/SQL: SQL Statement ignored 10/26 PL/SQL: ORA-00904: nome inválido de coluna

1.5.5. Utilização de procedimentos Os procedimentos podem ser chamados através do SQL*Plus, de outros procedimentos ou fun-ções ou de outros aplicativos pré compilados. Exemplo 1: Para chamar procedimentos a partir do prompt do SQL*Plus: Este exemplo utiliza a procedure reajuste que opera com parâmetros de entrada: SQL> execute reajuste(7934, 10) Procedimento PL/SQL concluído com sucesso. Exemplo 2: Para chamar o procedimento de um bloco PL/SQL anônimo: Este exemplo utiliza a procedure reajuste (que opera com parâmetros de entrada) e a procedure consulta_emp (que ope-ra com parâmetros de saída):

1. Editar as instruções em um arquivo com extensão sql

SQL> edit usa_proc.sql

ACCEPT p_cod PROMPT 'código do funcionário..... ' ACCEPT p_perc PROMPT 'percentual de aumento..... ' VARIABLE g_nome varchar2(25) VARIABLE g_sal number DECLARE

v_nome EMP.EMPR_NOME_DS%type; v_sal EMPR.sal%type;

BEGIN

SELECT EMPR_NOME_DS, sal INTO v_nome, v_sal FROM EMPR WHERE EMPRno = &p_cod; reajuste(&p_cod, &p_perc); consulta_emp(&p_cod, :g_nome, :g_sal);

END; / PRINT g_nome g_sal

Page 31: Apostila PLSQL

2. Execute o bloco

SQL> @ c:\usa_proc.sql

3. Resultado:

digite o código do funcionário..... 7934 digite o percentual de aumento..... 10 Procedimento PL/SQL concluído com sucesso.

Exemplo 3: Este exemplo utiliza a procedure formata_fone (que opera com parâmetros IN OUT). Digite no prompt do SQL:

Variable g_fone varchar2(15) Begin :g_fone := ‘01150819700’; end; / Print g_fone Execute formata_fone(:g_fone) Print g_fone

1.5.6. Passagem de Parâmetros A passagem de parâmetros pode ser feita de três maneiras:

• Por posição: Os parâmetros reais são listados de acordo com a ordem dos parâmetros for-mais.

• Por identificação: Os parâmetros reais são precedidos da identificação do parâmetro for-mal, podendo ser listados arbitrariamente.

• Combinada: Os parâmetros passados por posição devem ocupar os primeiros lugares da lista.

Exemplo:

CREATE OR REPLACE PROCEDURE incluir_dept (p_nome in dept.dname%type default ‘sem nome ainda’, p_loc in dept.loc%type default ‘NC’)

is

BEGIN Insert into dept(deptno, dname, loc) values(deptno_seq.nextval, p_nome, p_loc); END incluir_dept; /

A seguir são exemplificadas as maneiras possíveis de passagem de parâmetros para a utilização da procedure incluir_dept

• Por posição: SQL> EXECUTE incluir_dept; o próximo valor da sequence e os valores default se-rão incluídos seguindo a ordem de declaração dos parâmetros formais.

Page 32: Apostila PLSQL

SQL> EXECUTE Incluir_dept(‘R H’, ‘SC’); os parâmetros reais serão passados para os parâmetros formais de acordo com a ordem de declaração dos parâmetros for-mais.

• Por identificação: SQL> EXECUTE Incluir_dept( p_loc => ‘SP’, p_nome => ‘Treinamento’); os parâ-metros reais são precedidos da identificação dos parâmetros formais e do sinal de atribuição =>

• Por combinação: SQL> EXECUTE Incluir_dept(p_loc => ‘RJ’); os parâmetros que não estão listados receberão os valores defaut.

Resultado: SQL> select * from dept; DEPTNO DNAME LOC ---------- -------------- ------------- 10 ACCOUNTING 12 20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON 1 sem nome ainda NC 3 R H SC 4 Treinamento SP 5 sem nome ainda RJ 8 linhas selecionadas.

1.5.7. Aninhamento de procedimentos (subprocedimentos) Pode-se criar um procedimento dentro de outro procedimento, este recurso é chamado, também, de procedimentos em níveis. O exemplo a seguir cria a procedure exemplo_sub, nesta procedure está sendo criada uma outra procedure (log_usuário). Note que logo após a cláusula IS já é indi-cada a sub procedure, somente após a sua declaração completa que o corpo da procedure princi-pal é declarado.

CREATE OR REPLACE PROCEDURE exemplo_sub3

(p_id in EMPR_NUME_NR%type) IS

PROCEDURE log_usuario IS BEGIN

Insert into log_tabela (user_id, log_data) Values(user, sysdate);

END log_usuario; BEGIN Delete from EMPR Where EMPRno = p_id; END exemplo_sub;

Log_usuario;

/ A procedure principal (exemplo_sub) utiliza a sub procedure (log_usuário)., neste caso a tabela log_tabela irá guardar a identificação do usuário e a data da operação pois a procedure principal faz uma exclusão na tabela EMPR. 3 Não esqueça de criar a tabela para executar o exemplo: Create table log_tabela (user_id varchar2(10), log_data date);

Page 33: Apostila PLSQL

Utilização: SQL> execute exemplo_sub(7934); Procedimento PL/SQL concluído com sucesso. SQL> select * from log_tabela;

USER_ID LOG_DATA ---------- -------- SCOTT 29/04/04 1.6. Funções As funções são muito semelhantes aos procedimentos, o que as difere, do ponto de vista estrutu-ral, é a inclusão da cláusula return. A cláusula return também implementa a diferença conceitual entre as procedures e as functions, isto é, nas funções existe a obrigatoriedade de um retorno à ro-tina chamadora, pode-se dizer que uma função é chamada como parte de uma expressão. Sintaxe:

CREATE [ OR REPLACE] FUNCTION nome_função [parâmetro [in] tipo_parâmetro, ... return tipo_do_retorno

{IS ou AS} BEGIN corpo_da_função END nome_função;

onde:

Create or replace instrução para criação ou substituição do procedimento Nome_procedimento nome que será dado ao procedimento parâmetro [parâmetro [in] nome do parâmetro que poderá ser somente para entra-

da Tipo_parâmetro tipo de dado que o parâmetro poderá aceitar return tipo_do_retorno Indica o retorno do controle a rotina chamadora com o

valor que será devolvido IS ou AS tem a mesma função e indicam o bloco que estará asso-

ciado ao procedimento, substitui a palavra reservada DECLARE.

BEGIN corpo_do_procedimento END respectivamente o início do bloco, o conjunto de instru-ções do procedimento e o final do bloco.

Exemplos:

CREATE OR REPLACE FUNCTION descobrir_salario (p_id in EMP.EMPRno%type)

return number IS

vBEGIN

_salario EMPR.sal%type := 0;

Select sal into v_salario From EMPR Where EMPRno = p_id;

Page 34: Apostila PLSQL

Return v_salario; End descobrir_salario; /

Utilização:

SQL> variable g_sal number SQL> execute :g_sal := descobrir_salario(7900) SQL> print g_sal

ATENÇÃO: Uma função que contém instruções DML não pode ser utilizada no SQL em operações DML. O exemplo a seguir ilustra está situação:

CREATE OR REPLACE FUNCTION exemplo_dml (p_sal number)

return number IS BEGIN Insert into EMPR(EMPR_NUME_NR, EMPR_NOME_DS, sal, hiredate, deptno) Return (p_sal + 300);

Values(37, ‘Sandra’, p_sal, sysdate, 15);

End exemplo_dml; /

Utilização:

SQL> Update EMPR set sal = exemplo_dml(5000) Where EMPRno = 7900;

Erro ocasionado:

Update EMPR set sal = exemplo_dml(5000) * ERRO na linha 1: ORA-04091: a tabela SCOTT.EMP é mutante; talvez o gatilho/função não possa localizá-la ORA-06512: em "SCOTT.EXEMPLO_DML", line 6

1.7. Resumo das diferenças entre procedure e function Procedure Function É chamada em uma declaração SQL, blocos PL/SQL ou por uma aplicação

É chamada como parte de uma expressão

Não contém a clausula return no cabeçalho Contém a clausula return no cabeçalho Pode retornar nenhum, um ou vários valores Retorna somente um valor Pode devolver um retorno à rotina chamadora Retorna obrigatoriamente um valor para a rotina

chamadora. 1.8. Trigger São blocos PL/SQL ou Procedures PL/SQL associadas à tabelas, visões, esquemas ou bancos de dados. São disparados automaticamente antes ou depois da ocorrência de um evento. Podem ser classificados em:

• Trigger de aplicação – é disparado quando evento envolve uma aplicação em parti-cular, este tópico não será explorado.

Page 35: Apostila PLSQL

• Trigger de banco – é disparado quando ocorre uma operação DML para inserção, alteração ou exclusão de dados ou quando ocorre um evento associado ao banco, como exemplo o efetuar logon de um usuário. Podem ser implantados, entre outros, para:

o Implantação de regras de negócios

o Manutenção da integridade referencial

o Implantação de segurança

o Manutenção de um registro histórico das alterações

o Geração de valores de coluna, incluindo valores de chave primária

o Replicação de dados

Sintaxe: CREATE [OR REPLACE] TRIGGER [esquema.]nome_trigger {BEFORE ou AFTER} [evento]ON [esquema.]tabela_nome [referencing Old as valor_anterior ou NEW as valor_novo) {nível de linha ou nível de instrução} [WHEN (condição)]] DECLARE BEGIN corpo_trigger END; / onde:

Create or Replace Trigger instrução para criação ou substituição do Trigger

Esquema Nome do esquema ao qual pertence o objeto

Nome_trigger Identificador do trigger

Before Indica que a execução do trigger será antes da realização do evento

After Indica que a execução do trigger será depois da realização do evento

evento Define qual o tipo de instrução que irá provocar o disparo do trigger. As instruções possíveis são insert, update ou delete.

On tabela_nome Indica a tabela que está associada à instrução

Referencing Old as valor_anterior ou NEW as valor_novo

Especifica os identificadores das variáveis que irão armaze-nar os valores antigos e novos. Old e New sáo pseudo-colunas que auxiliam na manipulação das linhas afetadas.

Nível de linha É disparado uma vez para cada linha afetada pela instrução é identificado por FOR EACH ROW

Nível de instrução É disparado antes ou depois da instrução

When condição Só pode ser utilizada em trigger de linha. Indica que a trig-ger será disparada somente quando a condição for verda-deira.

Page 36: Apostila PLSQL

Exemplo 1: Criar um trigger para não permitir a inserção ou alterações da coluna salário para va-lores superiores a 15000, caso o cargo do funcionário não seja Presidente ou Vendedor. SQL> CREATE OR REPLACE TRIGGER restringe_salário 2 BEFORE Insert or Update OF sal ON Scott.emp 3 FOR EACH ROW 4 BEGIN 5 If not (:new.job in('PRESIDENT', 'SALES')) 6 And :new.sal > 15000 7 Then 8 RAISE_APPLICATION_ERROR(-20202, 'O funcionário não pode ter

este aumento de salário'); 9 END IF; 10 END; 11 /

Quando um usuário tentar realizar uma operação de inserção ou alteração que infrinja as regras definidas no trigger para o valor de salário, a mensagem de erro será apresentada conforme e-xemplo a seguir: SQL> insert into sCOTT.emp(EMPR_NUME_NR, EMPR_NOME_DS, EMPR_SERV_DS, sal, deptno) values 2* (135, 'MARCOS', 'CLERK', 15010, 10) * ERRO na linha 1: ORA-20202: O funcionario n?o pode ter este aumento de salario ORA-06512: em "SYS.RESTRINGE_SALARIO", line 5 ORA-04088: erro durante a execuc?o do gatilho 'SYS.RESTRINGE_SALARIO' ATENÇÃO: Os triggers não podem emitir commit ou rollback e não podem conter variáveis Long ou Long raw

Exemplo 2: Criar um trigger para não permitir a inserção de funcionários fora do horário comercial SQL> CREATE OR REPLACE TRIGGER seguro_emp 2 BEFORE INSERT ON SCOTT.EMP 3 BEGIN 4 IF(TO_CHAR(SYSDATE, 'DY') IN ('SAT','SUN')) OR 5 (TO_CHAR(SYSDATE, 'HH24:MI') 6 NOT BETWEEN '08:00' AND '18:00') 7 THEN RAISE_APPLICATION_ERROR(-20500, 'Inserções de funcionários so-

mente no horário comercial'); 8 end if; 9 end; 10 / A tentativa de inserir novos funcionários fora do horário previsto resultara no erro a seguir: SQL> insert into SCOTT.emp(EMPR_NUME_NR, EMPR_NOME_DS, sal, deptno) 2 values(7935, 'SANDRA', 1203, 10); insert into SCOTT.emp(EMPR_NUME_NR, EMPR_NOME_DS, sal, deptno) * ERRO na linha 1: ORA-20500: Inserc?es de funcionarios somente no horario comercial ORA-06512: em "SYS.SEGURO_EMP", line 5 ORA-04088: erro durante a execuc?o do gatilho 'SYS.SEGURO_EMP' Nos exemplos 1 e 2 o trigger é disparado sempre antes da ação ser concretizada, este é um re-curso útil para fazer validações, já no exemplo 3 é apresentado um trigger disparado depois de um evento, este recurso é útil para fazer auditoria, por exemplo.

Page 37: Apostila PLSQL

Exemplo: Criar um trigger para registrar as alterações realizadas em uma tabela, valores antigos e novos, os dados do usuário que realizou a alteração e a data da ocorrência: CREATE OR REPLACE TRIGGER auditar_emp AFTER DELETE OR INSERT OR UPDATE On Scott.emp FOR EACH ROW BEGIN INSERT INTO table_aud_emp(user_name, data,antigo_nome, novo_nome, anti-go_salario, novo_salario) values (user, sysdate, :old.ename,:new.ename,:old.sal, :new.sal); end; / Após a realização de qualquer operação DML a tabela de auditoria tabela_aud_emp receberá um registro com as informações do autor e data da operação, valores anteriores e valores atuais para nome e salário do funcionário, conforme o resultado apresentado a seguir: SQL> insert into SCOTT.emp(EMPR_NUME_NR, EMPR_NOME_DS, sal, deptno) 2 values(7935, 'SANDRA', 1203, 10); SQL> update scott.emp 2 set sal = 1300 3 where EMPR_NOME_DS = 'SANDRA'; Resultado: SQL> select * from table_aud_emp; USER_NAME DATA ID ANTIGO_NOME NOVO_NOME ANTIGO_SALARIO NOVO_SALARIO SYS 05/05/04 SANDRA 1203 SYS 05/05/04 SANDRA SANDRA 1203 1300 ATENÇÃO: Old e New sáo identificadores utilizados somente em triggers de linha, deve-se utilizar o prefixo : e fazer referência à coluna, por exemplo :old.ename. A tabela apresentada a seguir mostra os valores assumidos para :old e :new para cada evento: Evento :old :new INSERT Não deve ser definido, Todas as

colunas contém nulos. Novos valores que serão inseridos

UPDATE Valores das colunas antes da atu-alização (antigos)

Valores das colunas após a atualização (novos)

DELETE Valores das colunas antes da ex-clusão

Não deve ser definido, todas as colunas conterão nulos.

Select trigger_type, table_name, triggering_event From user_triggers Where...

Page 38: Apostila PLSQL

Para saber mais consulte: Livros: Autor Título Urman, Scott Urman, Scott, Oracle 8 Programação PL/SQL, McGraw Hill (1999) Oliveira, Celso H. Poderoso de

Oliveira, Celso H. Poderoso de, Oracle 8i Pl/Sql - Guia De Consul-ta Rapida, Novatec, 2000

Morelli, Eduardo Terra Morelli, Eduardo Terra, Oracle 8i Fundamental SQL, PL/SQL e Administração, Editora Érica, 2000

SILBERSCHATZ, Abraham, KORTH, Henry F. e SUDASRSHAN, S.,

Sistema de Banco de dados. São Paulo: Makron Books, 1999

Oracle8i – Administração de Bancos de Dados. Rio de Janeiro: Editora Ciência Moderna

Sites: Oracle http://otn.oracle.com/sample_code/tech/pl_sql/index.html imasters http://www.imasters.com.br SLQMagazine http://www.sqlmagazine.com.br Jose Valter http://josevalter.com.br/download/sql/Dicas%20Oracle%20SQL.PD

FStanford University http://www-db.stanford.edu/~ullman/fcdb/oracle/or-

plsql.html#variables%20and%20typesOracle http://www.orafaq.com/faqplsql.htm#WHATOracle http://otn.oracle.com/sample_code/tech/pl_sql/index.html imasters http://www.imasters.com.br SLQMagazine http://www.sqlmagazine.com.br

i Puga, Sandra, Rissetti, Gerson ...