Manual PL/SQL

27
Tutorial de PL/SQL Para Oracle 9 por Miguel Rodrigues Fornari

Transcript of Manual PL/SQL

Page 1: Manual PL/SQL

Tutorial de PL/SQLPara Oracle 9

por

Miguel Rodrigues Fornari

Page 2: Manual PL/SQL

Sumário1. Introdução...............................................................................................................3

2. Estrutura geral de um programa PL/SQL...............................................................3

2.1 Execução de PL/SQL........................................................................................4

3. Variáveis e constantes.............................................................................................5

3.1 Vetores..............................................................................................................6

3.2 Registros............................................................................................................6

3.3 Atribuição de valores à variáveis......................................................................7

3.4 Declaração de Constantes.................................................................................7

4. Cursores..................................................................................................................7

4.1 Laços FOR em Cursores...................................................................................9

4.2 Cursores Dinâmicos........................................................................................10

4.2.1 Manipulação de cursores dinâmicos........................................................11

5. Estruturas de Controle de Fluxo............................................................................12

5.1 Comando IF.....................................................................................................12

5.2 Comando CASE..............................................................................................12

5.3 Laços de iteração.............................................................................................13

5.3.1 Comando FOR-LOOP..............................................................................13

5.3.2 Comando WHILE-LOOP........................................................................13

5.3.3 Comando GOTO......................................................................................14

6. Modularidade........................................................................................................14

6.1 Subprogramas..................................................................................................14

6.2 Pacotes............................................................................................................16

6.3 Tratamento de exceções..................................................................................17

7. Funções pré-definidas...........................................................................................20

7.1 Funções de valor simples................................................................................20

7.1.1 Funções numéricas...................................................................................20

7.1.2 Funções de caracteres retornando caracteres...........................................21

7.1.3 Funções de caracteres que retornam valores numéricos..........................22

7.1.4 Funções de data........................................................................................22

7.1.5 Funções de conversão..............................................................................22

8. Visualização de valores na tela.............................................................................23

Page 3: Manual PL/SQL

1. Introdução

Este tutorial procurar resumir brevemente os principais pontos de PL/SQL, para o SGBD Oracle, versão 9. Não se trata de material completo, com todos os detalhes de sintaxe e semântica. É apenas um complemento para as aulas da disciplina de Bancos de Dados II, do curso de Sistemas de Informação, na ULBRA. Se o leitor necessitar, sugiro o material disponível no site Technet-Oracle (http://technet.oracle.com), especialmente o manual de usuário do PL/SQL (http://technet.oracle.com/docs/products/oracle9i/doc_library/release2/appdev.920/a96624/toc.htm), do qual os exemplos foram copiados e alguns trechos traduzidos.

2. Estrutura geral de um programa PL/SQL

Um modo interessante de entender PL/SQL é olhando inicialmente um programa exemplo. O programa abaixo processa uma ordem de compra de "Tennis Racket".

DECLARE qty_on_hand NUMBER(5);BEGIN SELECT quantity INTO qty_on_hand FROM inventory WHERE product = 'TENNIS RACKET' FOR UPDATE OF quantity; IF qty_on_hand > 0 THEN -- check quantity UPDATE inventory SET quantity = quantity - 1 WHERE product = 'TENNIS RACKET'; INSERT INTO purchase_record VALUES ('Tennis racket purchased', SYSDATE); ELSE INSERT INTO purchase_record VALUES ('Out of tennis rackets', SYSDATE); END IF; COMMIT;END;

Primeiro, declara uma variável to tipo NUMBER(5) para armazenar a quantidade de raquetes existentes. Então seleciona a quantidade existente em estoque, que está armazenada no banco, atribuindo o valor à variável qty_on_hand. Se a quantidade for maior que zero, atualiza o estoque e registra a venda, senão informa a falta do item.

PL/SQL trata-se de uma linguagem completa, no sentido em que possui comandos para declaração e manipulação de variáveis e controle de fluxo de processamento, definir procedimentos e funções, tratar erros, além de integrar comandos SQL. Não há comandos para vídeo ou teclado, que deverão ser controlados por outra linguagem. PL/SQL é uma linguagem estruturada em blocos (procedimentos, funções e blocos não nomeados), que podem conter zero ou mais sub-blocos. Tipicamente, cada bloco corresponde a um problema a ser resolvido. Em cada bloco é possível declarar variáveis de escopo local, que deixam de existir quando o bloco termina.

Page 4: Manual PL/SQL

Tipicamente, cada bloco é composto de três partes: declarações, comandos e tratamento de exceções. Apenas a seção de comandos é obrigatória.

[DECLARE declarações]

BEGINcomandos

[EXCEPTIONS tratamento de exceções]END;

2.1 Execução de PL/SQL

A execução de trechos de programas utilizando PL/SQL está integrada com o banco de dados. Em tempo de execução, Oracle identifica uma chamada a um bloco de comandos PL/SQL, identifica comandos SQL que podem ser resolvidos pelo engine do banco envia o restante do código para o excutor de PL/SQL, como mostra figura 1.

FIGURA 1. Esquema de execução de blocos de comandos PL/SQL.

Um procedimento ou função pode ser criado no banco de dados e utilizado por todas as aplicações e usuários que tiverem direito, através de um comando CALL. Estes procedimentos são chamados de Stored Procedures.

3. Variáveis e constantes

PL/SQL permite declarar variáveis e constantes e utilizá-las em qualquer comando ou expressão dentro do seu escopo. As variáveis devem ser declaradas antes de serem utilizadas. Variáveis podem ser de qualquer tipo pré-existente no SQL, a saber:

CHAR(num_caracteres): permite armazenar strings com um tamanho máximo delimitado.

VARCHAR2(num_caracteres): permite armazenar strings com um tamanho máximo delimitado. A diferença com anterior está em não armazenar caracteres em branco ao final da string. Disto resulta algumas situações não habituais, após as atribuições realizadas.

Page 5: Manual PL/SQL

C1 CHAR(10);VC1 VARCHAR2(10);VC2 VARCHAR2(10);C1 = 'RICO 'VC1 = 'RICO 'VC2 = 'RICO'

A partir das declarações das variáveis e atribuições acima, tem-se que VC1 é diferente que C1, pois apenas C1 conserva os espaços em branco ao final, enquanto VC1 não os conserva, porém VC1 = VC2.

BYNARY_INTEGER: números inteiros entre -231 até 231 -1 .

NUMBER([núm_dígitos, precisão]): suporta números entre 1-130 e 10125, com um certo número de casas decimais, especificadas no parâmetro precisão.

Este tipo possui alguns subtipos. DOUBLE PRECISION e FLOAT permitem até 38 casas decimais de precisão, enquanto REAL permite apenas 18 casas decimais. INT, INTEGER e SMALLINT representam números inteiros de até 18 dígitos.

PLS_INTEGER: também armazena números inteiros entre –2-31 até 231 -1, porém as funções matemáticas operam com maior eficiência sobre variáveis deste tipo, sendo preferível para cálculos mais complexos.

BOOLEAN: variáveis booleanas podem armazenar os valores TRUE, FALSE e NULL.

DATE: armazena valores de data, incluindo o horário. O formato default para datas está definido em um parâmetro do Oracle, chamado NLS_DATE_FORMAT.

TIMESTAMP: este tipo armazena a data, hora, minutos e segundos. Por exemplo, '1999-06-22 07:48:53.275'.

TIMESTAMP WITH TIME ZONE: este tipo inclui a zona de tempo. Por exemplo, '1999-10-31 09:42:37.114 +02:00'.

A declaração de variáveis está mostrada nos exemplos abaixo, com o nome da variável seguido pelo tipo.

part_no NUMBER(4);in_stock BOOLEAN;

3.1 Vetores

O tipo VARRAY permite declarar vetores, compostos por uma coleção ordenada de elementos do mesmo tipo. Cada elemento possui um índice único, que indica sua posição no vetor. Não é necessário indicar um tamanho máximo para o vetor. Depois de criado o tipo, podem ser declaradas uma ou mais variáveis do tipo. A sintaxe de criação do tipo é:

Page 6: Manual PL/SQL

TYPE type_name IS VARRAY [(limite_tamanho) ] OF element_type [NOT NULL];

Para se referir a um elemento, utiliza-se o índice entre parênteses. Por exemplo:

DECLARE TYPE Staff IS VARRAY OF Employee; staffer Employee; FUNCTION new_hires (hiredate DATE) RETURN Staff IS BEGIN ... END;BEGIN staffer := new_hires('10-NOV-98')(5);END;

3.2 Registros

Registros permitem a composição de variáveis de tipos diferentes em um mesmo grupo lógico. Os nomes dos campos devem ser únicos. Um campo pode ser de um tipo registro ou vetor, de modo ortogonal. Uma vez criado o tipo registro, podem ser declaradas variáveis deste tipo. Por exemplo:

DECLARE TYPE TimeRec IS RECORD (hours SMALLINT, minutes SMALLINT); TYPE MeetingTyp IS RECORD ( date_held DATE, duration TimeRec, -- nested record location VARCHAR2(20), purpose VARCHAR2(50));

3.3 Atribuição de valores à variáveis

É possível atribuir valores a variáveis de três maneiras. A mais comum é o operador de atribuição (:=), como mostram os exemplos abaixo.

tax := price * tax_rate;valid_id := FALSE;bonus := current_salary * 0.10;wages := gross_pay(emp_id, st_hrs, ot_hrs) - deductions;

A segunda maneira de atribuir valores é utilizando o comando SELECT é atribuindo seu retorno à uma variável. O comando SELECT deve ser construído de modo a retornar um valor, não uma lista de valores. Por exemplo, atribuir 10% do salário para a variável bonus.

SELECT sal * 0.10 INTO bonus FROM emp WHERE empno = emp_id;

A terceira maneira de atribuir valores é através de passagem de parâmetros em chamadas de procedimentos e funções, o que será visto mais adiante.

3.4 Declaração de Constantes

A declaração de constantes é semelhante à de variáveis, acrescentando a palavra

Page 7: Manual PL/SQL

chave CONSTANT e, imediatamente, atribuindo o valor. Por exemplo,

credit_limit CONSTANT REAL := 5000.00;

4. Cursores

Oracle utiliza áreas de trabalho para executar comandos SQL e armazenar a informação processada. Um cursor permite percorrer esta área de trabalho para ler as informações armazenadas. Há dois tipos de cursores: implícitos e explícitos. Cursores implícitos são criados pelo Oracle a cada execução de um comando SQL, mas não podem ser utilizados em um programa em PL/SQL. Cursores explícitos podem ser manipulados em um programa PL/SQL.

A declaração de um cursor segue a sintaxe DECLARE CURSOR nome_cursor IS comando_select; Por exemplo,

DECLARE

CURSOR c1 IS

SELECT empno, ename, job FROM emp WHERE deptno = 20;

A declaração do cursor associa um comando SQL a ele. Um curso permitirá ler, tupla a tupla, o resultado de um consulta. A semelhança de um arquivo, o cursor deve ser aberto, percorrer uma a uma cada tupla, até o final do conjunto de dados.

FIGURA 1. Cursor

O programa de utilizar os comandos OPEN, FETCH e CLOSE. O comando OPEN executa a consulta associada ao cursor, obtém um conjunto de tuplas como resposta a consulta e posiciona o cursor na primeira tupla. O comando FETCH retorna os valores da tupla corrente e avança uma posição na lista. O comando CLOSE desabilita o cursor, liberando o espaço de memória ocupado pelo conjunto resposta.

A sintaxe do comando OPEN é:

OPEN nome_cursor;

A sintaxe do comando CLOSE é:

CLOSE nome_cursor;

E do comando FETCH é

FETCH nome_curso INTO [lista_variáveis].

A lista de variáveis pode conter uma ou mais variáveis. Há duas alternativas: utilizar

Page 8: Manual PL/SQL

variáveis individuais, de tipos correspondentes ao retorno do SELECT; ou utilizar uma variável de um tipo registro adequado ao SELECT. Para o cursor declarado acima, é possível:

FETCH c1 INTO my_empno, my_ename, my_deptno;

ou

FETCH c1 INTO my_record;

Todos cursores possuem quatro propriedades que podem ser úteis em um programa:

%FOUND: indica se a última operação FETCH encontrou uma tupla. Seu valor é verdadeiro até a última tupla.

%NOTFOUND: indica se a última operação FETCH não encontrou uma tupla. Seu valor é falso até a última tupla.

%ISOPEN: indica se o cursor está aberto ou não.

%ROWCOUNT: retorna o número de tuplas do cursor.

Para testar se o cursor retornou algum valor válido ou já atingiu o final do conjunto, pode-se testar a propriedade FOUND do cursor. Por exemplo,

FETCH C1 INTO ....WHILE C1%FOUND LOOP Comandos FETCH C1 INTO ....END LOOP

Um cursor pode, ainda, ter parâmetros. Deste modo, a definição do cursor fica alterada:

DECLARE CURSOR emp_cursor(dnum NUMBER) IS SELECT sal, comm FROM emp WHERE deptno = dnum;

A inicialização do cursor, que pode ser por um comando OPEN ou FOR-LOOP é feita passando o valor do parâmetro. Por exemplo:

FOR emp_record IN emp_cursor(20) LOOP … END IF; END LOOP;

Page 9: Manual PL/SQL

4.1 Laços FOR em Cursores

Em muitas situações, percorrer todas as tuplas resultantes de uma tabela pode ser realizado com o comando FOR, e não com OPEN-FETCH-CLOSE. Um laço FOR em cursores exige uma variável, que é declarada implicitamente dentro do comando. No exemplo abaixo, a variável emp_rec é do tipo registro. Para referir campos individuais da variável, é utilizada a notação ponto (.).

DECLARE CURSOR c1 IS SELECT ename, sal, hiredate, deptno FROM emp; ...BEGIN FOR emp_rec IN c1 LOOP ... salary_total := salary_total + emp_rec.sal; END LOOP;

4.2 Cursores Dinâmicos

Embora a maioria dos programas em PL/SQL execute comandos previsíveis, que permitem uma declaração estática de um cursor, em algumas situações é necessário alterar dinamicamente, em tempo de execução, o comando SELECT que define o cursor. As seguintes situações são típicas:

É necessário utilizar um comando de definição de dados (DDL), como o CREATE, um comando de atribuição ou revogação de direitos (GRANT e REVOKE) OU UM comando de CONTROLE de sessão (ALTER SESSION). Em PL/SQL, estes comandos são necessariamente dinâmicos.

É necessário compor a clausula WHERE de acordo com condições que o usuário escolhe ou não na interface.

O comando adequado é o EXECUTE IMMEDIATE, cuja sintaxe é:

EXECUTE IMMEDIATE comando_sql[INTO {variável1, variável2, …. ]... | variável_registro}][USING parâmetro1, parâmetro2, ...};

O comando SQL é especificado na primeira. Na clausula INTO, indica-se as variáveis que receberão o retorno do comando, ou apenas uma variável do tipo registro. Na clausula USING indica-se os parâmetros do comando. Abaixo há um conjunto de exemplos:

EXECUTE IMMEDIATE 'ALTER SESSION SET SQL_TRACE TRUE'; - executa o comando ALTER SESSION.

Page 10: Manual PL/SQL

EXECUTE IMMEDIATE 'CREATE TABLE bonus (id NUMBER, amt NUMBER)'; - executa o comando de criação de uma tabela.

sql_stmt := 'INSERT INTO dept VALUES (:1, :2, :3)'; EXECUTE IMMEDIATE sql_stmt USING dept_id, dept_name, location; - executa o

comando INSERT, colocando os valores passados por parâmetro na clausula USING.

sql_stmt := 'SELECT * FROM emp WHERE empno = :1'; EXECUTE IMMEDIATE sql_stmt INTO emp_rec USING emp_id; - executa o

commando SELECT, atribuindoa resposta à variável emp_rec. A identificação do empregado é passada por parâmetro.

EXECUTE IMMEDIATE 'DELETE FROM dept WHERE deptno = :num' USING dept_id; - retira uma tupla da tabela dept.

4.2.1 Manipulação de cursores dinâmicos

No caso de comandos SELECT que retornem mais de uma tupla no conjunto resposta, é necessário utilizar os comandos OPEN-FETCH-CLOSE para percorrer, tupla a tupla, o conjunto resposta.

Para o comando OPEN utiliza-se a seguinte variação sintática:

OPEN {variável_cursor } FOR string_sql [USING argumento1[, argumento2]...];

Uma variável do tipo cursor deve declarada, a priori. O comando SQL é montado em uma variável do tipo string, conforme a necessidade do programa, e colocado na clausula FOR. Se houverem parâmetros no comando SQL, os argumentos são passados na clausula USING. O exemplo abaixo ilustra este caso. Veja que a variável emp_cv é declarada como sendo do tipo cursor e no comando SELECT há um parâmetro, cujo valor é atribuído na clausula USING.

DECLARE TYPE EmpCurTyp IS REF CURSOR; -- define weak REF CURSOR type emp_cv EmpCurTyp; -- declare cursor variable my_ename VARCHAR2(15); my_sal NUMBER := 1000;BEGIN OPEN emp_cv FOR -- open cursor variable 'SELECT ename, sal FROM emp WHERE sal > :s' USING my_sal; ...END;

Os comandos FETCH e CLOSE permanecem semelhantes, como mostra o trecho de código a seguir:

FETCH emp_cv INTO my_ename, my_sal; WHILE emp_cv%FOUND = TRUE LOOP

- - comandosFETCH emp_cv INTO my_ename, my_sal;

END LOOP;CLOSE emp_cv; -- close cursor variable

Page 11: Manual PL/SQL

5. Estruturas de Controle de Fluxo

As estruturas de controle de fluxo de comandos permitem definir a execução dos comandos de acordo com uma seqüência adequada. PL/SQL possui os comandos IF-THEN-ELSE, CASE, FOR-LOOP, WHILE-LOOP, EXIT-WHEN, e GOTO.

5.1 Comando IF

O comando IF-THEN-ELSE permite escolher entre dois caminhos alternativas, de acordo com uma condição booleana. Por exemplo,

IF acct_balance >= debit_amt THEN UPDATE accounts SET bal = bal - debit_amt WHERE account_id = acct; ELSE INSERT INTO temp VALUES (acct, acct_balance, 'Insufficient funds'); -- insert account, current balance, and message END IF;

5.2 Comando CASE

Para escolher entre várias alternativas (valores, comandos), pode utilizar o comando CASE. Cada condição é expressa em uma clausula WHEN e a ação associada através da palavra-chave THEN. Por exemplo, o comando abaixo possui quatro alternativas, uma para quadrados (square), para círculos (circle), retângulos (rectangle) e outra alternativa para os demais casos (ELSE).

-- This CASE statement performs different actions based-- on a set of conditional tests.CASE WHEN shape = 'square' THEN area := side * side; WHEN shape = 'circle' THEN BEGIN area := pi * (radius * radius); DBMS_OUTPUT.PUT_LINE('Value is not exact because pi is irrational.'); END; WHEN shape = 'rectangle' THEN area := length * width; ELSE BEGIN DBMS_OUTPUT.PUT_LINE('No formula to calculate area of a' || shape); RAISE PROGRAM_ERROR; END;END CASE;

5.3 Laços de iteração

Em PL/SQL existem os seguintes laços de iteração:

Page 12: Manual PL/SQL

5.3.1 Comando FOR-LOOP

O comando FOR-LOOP permite executar uma seqüência de comandos um número determinado de vezes. A sintaxe é:

FOR variável IN limite_inferior..limite superior LOOP -- comandosEND LOOP;

Por exemplo, o comando FOR-LOOP repete 500 vezes o comando INSERT.

FOR num IN 1..500 LOOP INSERT INTO roots VALUES (num, SQRT(num));END LOOP;

5.3.2 Comando WHILE-LOOP

O comando WHILE-LOOP executa uma seqüência de comandos até que uma condição lógica resulte falsa. A condição lógica é avaliada antes da execução dos comandos.

A sintaxe é:

WHILE condição_Lógica LOOP ComandosEND LOOP;

Por exemplo, no trecho abaixo o comando SELECT é executado enquanto a variável for menor que 2500.

WHILE salary <= 2500 LOOP SELECT sal, mgr, ename INTO salary, mgr_num, last_name FROM emp WHERE empno = mgr_num; END LOOP;

5.3.3 Comando GOTO

O comando GOTO permite alterar a seqüência de execução sem nenhuma condição, para qualquer ponto do programa, indicado por um label. O label é indicado por um nome entre dois sinais de menor e dois de maior, como mostra o exemplo abaixo:

IF rating > 90 THEN GOTO calc_raise; -- branch to labelEND IF;...<<calc_raise>>IF job_title = 'SALESMAN' THEN -- control resumes here amount := commission * 0.25;ELSE amount := salary * 0.10;END IF;

Page 13: Manual PL/SQL

6. Modularidade

Modularidade permite dividir uma aplicação em trechos menores, mais fáceis de serem desenvolvidos e testados. PL/SQL permite a criação de procedimentos, funções e pacotes.

6.1 Subprogramas

PL/SQL possui dois tipos de subprogramas, chamados procedimentos e funções, que podem receber parâmetros. Um subprograma deve ser declarado antes de ser chamado.

A declaração de um procedimento segue a seguinte sintaxe:

PROCEDURE nome_procedimento [(lista_de_parâmetros)] IS [declarações locais] BEGIN comandos [ EXCEPTION tratamento de exceções ] END ;

Onde,

lista_de_parâmetros := [IN | OUT | INOUT] nome_parâmetro1 tipo_parâmetro1 [, [IN | OUT | INOUT] nome_parâmetro2 tipo_parâmetro2] ... [, [IN | OUT | INOUT] nome_parâmetroN tipo_parâmetroN]

A lista de parâmetros é opcional e pode ter um ou mais parâmetros. Cada parâmetro pode ser IN, OUT ou INOUT. Parâmetros IN são o tipo default, permitem receber um valor para o procedimento utilizar. Parâmetros OUT têm seu valor alterado durante o procedimento e parâmetros INOUT combinam os dois tipos.

O exemplo abaixo ilustra um procedimento.

PROCEDURE award_bonus (emp_id NUMBER) IS bonus REAL; comm_missing EXCEPTION;BEGIN -- executable part starts here SELECT comm * 0.15 INTO bonus FROM emp WHERE empno = emp_id; IF bonus IS NULL THEN RAISE comm_missing; ELSE UPDATE payroll SET pay = pay + bonus WHERE empno = emp_id; END IF;EXCEPTION -- exception-handling part starts here WHEN comm_missing THEN ...END award_bonus;

A chamada de uma função é realizada apenas através do nome do procedimento e os parâmetros. Os parâmetros são posicionais, como no PASCAL e C. Por exemplo,

BEGIN ....

Page 14: Manual PL/SQL

award_bônus(304); ….END;

A sintaxe para funções inclui o tipo de retorno da função, como abaixo:

FUNCTION function_name [ ( lista_de_parâmetros ) ] RETURN tipo_de_dados [declarações locais] BEGIN comandos [ EXCEPTION tratamento de exceções ] END ;

O exemplo abaixo ilustra uma função. O comando RETURN específica o valor retornado pela função.

FUNCTION sal_ok (salary REAL, title VARCHAR2) RETURN BOOLEAN IS min_sal REAL; max_sal REAL;BEGIN SELECT losal, hisal INTO min_sal, max_sal FROM sals WHERE job = title; RETURN (salary >= min_sal) AND (salary <= max_sal);END;

A chamada de funções também é semelhante ao Pascal e C, bastando utilizar o nome da função. Uma função pode ser utilizada em qualquer contexto possível para um valor do mesmo tipo. Por exemplo,

IF sal_ok( 20000, ‘A’) THEN ….END IF;

6.2 Pacotes

Um conjunto de variáveis, cursores e procedimentos e funções podem ser agrupados logicamente em pacotes. Um pacote é composto de duas partes: especificação e implementação. A especificação permite a declaração de variáveis, cursores, tratadores de exceções e cabeçalhos de procedimentos e funções. A implementação contém os procedimentos e funções completas.

O exemplo abaixo declara um pacote, chamado emp_actions, composto de dois procedimentos, hire_employee e fire_employee.

CREATE PACKAGE emp_actions AS -- package specification PROCEDURE hire_employee (empno NUMBER, ename CHAR, ...); PROCEDURE fire_employee (emp_id NUMBER);END emp_actions;

Page 15: Manual PL/SQL

CREATE PACKAGE BODY emp_actions AS -- package body PROCEDURE hire_employee (empno NUMBER, ename CHAR, ...) IS BEGIN INSERT INTO emp VALUES (empno, ename, ...); END hire_employee; PROCEDURE fire_employee (emp_id NUMBER) IS BEGIN DELETE FROM emp WHERE empno = emp_id; END fire_employee;END emp_actions;

Apenas o que foi declarado na especificação do pacote é visível externamente. Um pacote pode ser compilado e armazenado no Oracle, podendo ser utilizado por várias aplicações.

6.3 Tratamento de exceções

Quando um erro ocorre em PL/SQL, uma exceção é disparada, a exceção normal do programa para e o fluxo de controle do programa é desviado para o tratamento de exceções associado ao programa ou procedimento. O Oracle trata automaticamente uma série de exceções, como divisão por zero, mas de uma forma padronizada, que consiste em mostrar a mensagem de erro gerada pelo Oracle para o usuário, o que, em geral, não é recomendável.

Há um grande conjunto de exceções no Oracle. Abaixo estão listadas as principais:

Exceção Ocorre quando ...

ACCESS_INTO_NULL O programa tentou atribuir valores nulos a variáveis.

CASE_NOT_FOUND Nenhuma das codices das claúsulas WHEN de um comando CASE foi atentida e não há claúsula ELSE.

CURSOR_ALREADY_OPEN Foi realizada uma tentativa de abrir um cursor (comandos OPEN ou FOR) que já está aberto.

DUP_VAL_ON_INDEX Inserção de um valor duplo em um campo de valores únicos.

INVALID_CURSOR Operação ilegal em um cursor, como fechar um cursor não aberto.

INVALID_NUMBER A conversão de uma variável do tipo caracter para outra do tipo numérico não foi possível.

LOGIN_DENIED Usuário ou senha incorretos.

Page 16: Manual PL/SQL

Exceção Ocorre quando ...

NO_DATA_FOUND Um comando SELECT INTO não retornou nenhum valor para a variável.

NOT_LOGGED_ON O usuário não está logado ao Oracle.

PROGRAM_ERROR Erro interno do PL/SQL.

ROWTYPE_MISMATCH Atribuição de uma coluna de um cursor para uma variável de tipo incorreto.

STORAGE_ERROR Erro interno no armazenamento de dados em memória.

SUBSCRIPT_BEYOND_COUNT O programa tentou acessar um elemento acima do limite máximo do array.

SUBSCRIPT_OUTSIDE_LIMIT O programa tentou acessar um elemento abaixo do limite mínimo do array.

TIMEOUT_ON_RESOURCE Ocorreu um time-out na busca por um recurso necessário para o processamento de um comando SQL.

TOO_MANY_ROWS Um comando SELECT INTO retornou mais de um valor.

VALUE_ERROR Ocorreu um erro em uma expressão aritmética ou função de conversão de valores.

ZERO_DIVIDE Divisão por zero.

O exemplo abaixo mostra o tratamento de exceções. O programa prevê um tipo de tratamento diferente para a divisão por zero.

DECLARE pe_ratio NUMBER(3,1);BEGIN SELECT price / earnings INTO pe_ratio FROM stocks WHERE symbol = 'XYZ'; -- might cause division-by-zero error INSERT INTO stats (symbol, ratio) VALUES ('XYZ', pe_ratio); COMMIT;EXCEPTION -- exception handlers begin WHEN ZERO_DIVIDE THEN -- handles 'division by zero' error INSERT INTO stats (symbol, ratio) VALUES ('XYZ', NULL); COMMIT;

Page 17: Manual PL/SQL

... WHEN OTHERS THEN -- handles all other errors ROLLBACK;END;

Em um programa, é possível ainda declarar novas exceções, como mostra o exemplo abaixo.

DECLARE ... comm_missing EXCEPTION; -- declare exceptionBEGIN ... IF commission IS NULL THEN RAISE comm_missing; -- raise exception END IF; bonus := (salary * 0.10) + (commission * 0.15);EXCEPTION WHEN comm_missing THEN ... -- process the exception

Finalmente, o Oracle possui um grande número de códigos de erro, que podem ser manipulados no tratamento da exceção, através das variáveis SQLCODE (código numérico) e SQLERRM (mensagem de erro). Estas variáveis não podem ser utilizadas diretamente em um comando SQL, devendo ser atribuídas a variáveis locais. Por exemplo:

DECLARE err_num NUMBER; err_msg VARCHAR2(100);BEGIN ...EXCEPTION WHEN OTHERS THEN err_num := SQLCODE; err_msg := SUBSTR(SQLERRM, 1, 100); INSERT INTO errors VALUES (err_num, err_msg);END;

7. Funções pré-definidas

O SQL Oracle possui um grande conjunto de funções pré-definidas, que podem ser utilizadas pelo programador. Estas funções dividem-se em dois grupos: valores simples, que retornam apenas um valor como resultado; e valores múltiplos, que podem retornar uma tabela de valores. O que segue não é uma lista exaustiva de todas as funções. Para tanto, o leitor pode consultar o manual on-line, no endereço http://technet.oracle.com/docs/products/oracle9i/doc_library/901_doc/server.901/a90125/functions2.htm#80856.

Page 18: Manual PL/SQL

7.1 Funções de valor simples

Funções de valor simples estão presentes em praticamente todas as linguagens. Sua chamada é realizada atribuindo o valor e retorno a uma variável ou utilizando a função em uma expressão mais complexa.

7.1.1 Funções numéricas

Funções numéricas aceitam valores de entrada numéricos e retornam valores numéricos. A maioria delas retornam valores exatos até 38 casas decimais. As funções trigonométricas COS, COSH, EXP, LN, LOG, SIN, SINH, SQRT, TAN, e TANH são acuradas até 36 casas decimais. As funções trigonométricas inversas ACOS, ASIN, ATAN e ATAN2 tem precisão de 30 casas decimais. As funções numéricas são:

ABS( número ): valor absoluto do número .

ACOS ( número ): valor, em radianos, do arco cosseno.

ASIN ( número): valor, em radianos, do arco seno.

ATAN (número): valor, em radianos, do arco tangente.

CEIL (número): menor inteiro maior ou igual ao parâmetro.

COS (número): valor do cosseno de um ângulo.

COSH (número): valor do cosseno hiperbólico de um ângulo.

EXP (número): resultado de enúmero.

FLOOR (número): menor inteiro menor ou igual ao parâmetro.

LN (número): logaritmo neperiano do parâmetro.

LOG (número): logaritmo na base 10 do parâmetro.

MOD ( dividendo, divisor): calcula o resto da divisão.

POWER (n1, n2): calcula n1n2.

ROUND (número): arredondamento do parâmetro.

SIGN (número): se número<0, retorna -1. Se número=0, returna 0. Se n>0, returna 1.

SIN (número): valor do seno de um ângulo.

SINH (número): valor do seno hiperbólico de um ângulo.

SQRT (número): valor da raiz quadrada de um número.

TAN (número): valor do tangente de um ângulo.

TANH (número): valor do tangente hiperbólica de um ângulo.

TRUNC (valor, precisão) : realiza o truncamento do valor para um número de casas decimais indicado como precisão.

Page 19: Manual PL/SQL

7.1.2 Funções de caracteres retornando caracteres

As funções de caracteres retornam um tipo adequado com o parâmetro de entrada. Se o parâmetro de entrada for CHAR, o retorno será CHAR, limitado até 2000 caracteres. Se for VARCHAR2, o retorno será VARCHAR2, limitado a te 4000 caracteres. São as seguintes funções:

CHR (número): retorna o caractere equivalente ao código ASCII passado por parâmetro.

CONCAT (string1, string2): retorna a string resultante da concatenação dos parâmetros.

INITCAP (string): retorna um string com a primeira letra maiúscula e as demais minúsculas.

LOWER (string): retornar um string com todas as letras minúsculas.

REPLACE (string, caracter1, caracter2): troca todas as ocorrências do caracter1 pelo caracter2;

SUBSTR(string, posição, num_caracteres): retorna a substring que começa na posição indicada, com um certo número de caracteres.

TRIM( caracter FROM string): retorna a string original sem as ocorrências do caracter indicado. A palavra chave FROM é necessária.

Ex: TRIM( 0 FROM 002939940) = 293994

UPPER( string): retorna a string com todos os caracteres em maiúsculo.

7.1.3 Funções de caracteres que retornam valores numéricos

No PL/SQL as seguintes funções retornam valores numéricos:

ASCII(caracter): retorna o código ASCII correspondente ao caracter.

INSTR(string, substring): retorna a posição da primeira ocorrência da substring dentro do string. Ex: INSTR(“ORACLE”, “C”) = 4.

LENGTH(string): retorna o número de caracteres da string.

7.1.4 Funções de data

Funções de data são aquelas aplicáveis a valores do tipo DATE. Com exceção das funções indicadas, todas retornam uma data válida.

ADD_MONTHS ( data, valor): adiciona um certo número de meses, indicado no parâmetro valor, a data.

CURRENT_DATE : retorna a data atual.

EXTRACT (campo FROM DATE data): extrai da data o valor do campo indicado. As palavras chaves para indicar os campos são:YEAR,

Page 20: Manual PL/SQL

MONTH, DAY, HOUR, MINUTE, SECOND. Ex: EXTRACT(YEAR FROM DATE '1998-03-07') = 1998.

LAST_DAY (data): retorna o ultimo dia do mês a qual a data pertence.

MONTHS_BETWEEN ( data1, data2): retorna o número de meses entre data1 e data2. Se data1 for posterior, o valor será positivo. O Oracle a fração correspondente ao mês, quando necessário. Ex: MONTHS_BETWEEN ('02-02-1995','01-01-1995') = 1.03225806.

NEXT_DAY (data): retorna o próximo dia útil.

SYSDATE : retorna dia e hora correntes.

TRUNC (data, ‘MONTH’ ou ‘YEAR’): trunca a data para o primeiro dia do mês ou ano correspondente a data, conforme indicado como unidade. EX: TRUNC(27-OCT-92,'YEAR') = 01-JAN-92.

7.1.5 Funções de conversão

Funções de conversão convertem um valor de um tipo de dados para outro. Geralmente o primeiro tipo é de entrada e o segundo tipo de saída.

CAST(valor AS tipo): converte um valor especificado para um tipo de dado pré-definido ou criado pelo usuário. EX: CAST('22-OCT-1997' AS DATE)= 22-10-1997.

TO_CHAR (datetime): converte um tipo de tempo (data ou hora) para VARCHAR2.

TO_CHAR (number) : converte um valor numérico para VARCHAR2.

TO_DATE (string): converte um string para data ou hora.

TO_NUMBER (string): converte uma string para um valor numérico.

8. Visualização de valores na tela

Oracle possui vários pacotes de procedimentos, que podem ser utilizados conforme a conveniência do programador/analista. Um destes pacotes chama-se DBMS_OUTPUT. Ele permite montar uma saída para o usuário. São basicamente três procedimentos:

PUT(conteudo): coloca o conteudo na saída

NEW_LINE: imprime a saída, acrescenta uma quebra de linha.

PUT_LINE(conteudo): imprime o conteudo, já com a quebra de linha.Apenas um valor pode ser passado como parâmetro.

No exemplo abaixo, utiliza-se concatenação para o label mais a variável. São vários comandos PUT, concluídos com um NEW_LINE.

Exemplo:create or replace procedure lista_vendas(seq number)Is

i number(5); nf number(10);

Page 21: Manual PL/SQL

dv date; val number(12,2); cursor c1 is

select nfiscal, datav, valor from vendas order by valor desc;

beginopen c1; for i in 1..seq loop

fetch c1 into nf, dv, val; if c1%found then

dbms_output.put('Ordem : ' || i);dbms_output.put(' Nota Fiscal: ' || nf);dbms_output.put(' Data da Venda: ' || dv);dbms_output.put(' Valor: R$'|| val);dbms_output.new_line;

elseexit;

end if;end loop;close c1;

end;

A saída deve ser semelhante a:

SQL> exec lista_vendas(10);Ordem : 1 Nota Fiscal: 1011 Data da Venda: 20/08/02Valor: R$300Ordem : 2 Nota Fiscal: 1010 Data da Venda: 20/08/02Valor: R$200Ordem : 3 Nota Fiscal: 3 Data da Venda: 19/08/02Valor: R$50Procedimento PL/SQL concluído com sucesso