administracao de banco de dados
TRANSCRIPT
-
Administrao de Banco de DadosLinguagem PL/SQL
Prof. Dr. Wagner J. [email protected]
Lins-SP, Agosto de 2012
-
Apresentao da Disciplina
Ementa: PL/SQL: blocos annimos, cursores, stored procedures,
functions, triggers.
Critrios de Aproveitamento: Provas: peso 8.0 (oito) Trabalhos: peso 2.0 (dois)
2
-
BibliografiaLivro Texto:1. Introduo a Sistemas de Banco de Dados; Date, C. J.; Ed. Campus; 8 edio; 2004;
15 exemplares.2. Sistemas de Banco de Dados; Korth, Henry F.; Ed. Campus; 5 edio; 2006; 15
exemplares.3. Oracle Database 11g PL/SQL: Programao; McLaughlin, Michel; Ed. Novatec; 1
edio; 2009; 10 exemplares.
Complementar:4. Projeto e Modelagem de Banco de Dados; Lightstone, Teorey; Ed. Campus; 1 edio;
2006; 10 exemplares.5. Oracle 10g PL/SQL; Oliveira, Celso H. Poderoso de; Ed. Novatec; 1 edio; 2005; 10
exemplares.6. Oracle 10g Database: Guia do DBA; Serson, Roberto Rubinstein; Ed. Novatec; 1 edio;
2004; 10 exemplares.7. Oracle 10g: Ideal Para Quem Deseja Iniciar o Aprendizado do Oracle; Ramalho, Jos
A.; Ed. Thomson; 1 edio; 2005; 10 exemplares.8. Gerenciando Banco de Dados: A Abordagem Entidade-Relacionamento para Projeto
Lgico; Chen, Peter; Makron Books; 1 edio; 1990; 7 exemplares.
3
-
Linguagem PL/SQL
Definio Blocos annimos Cursores Stored procedures Functions Triggers
4
-
Oracle 11g
Instalao e Servios iSQLPlus Criao de um usurio DBA
5
-
Instalao e Servios
No Windows, possvel realizar a instalao default, sem alterar as configuraes padres. Mas fique atento para anotar a senha inicial que solicitada ao usurio SYSTEM (Administrador).
Se voc possui um computador com 512Mb de memria (o ideal 1Gb) e processador acima de 2GHertz, pode instalar a verso completa do Oracle 11g. O disco de instalao tem cerca de 600Mb.
Para mquinas mais antigas, recomenda-se o uso do Oracle 11g Express Edition. A configurao mnima 256Mb e 1GHertz. O instalador tem cerca de 250Mb.
Obs.: Somente a verso 11g Express Edition gratuita para uso comercial (limitado a 1 base de dados de 4Gb).
6
-
Instalao e Servios (cont.)
Afim de carregar o Oracle somente quando realmente desejar utiliz-lo, coloque os 3 servios listados a seguir para serem iniciados manualmente. ORACLESERVICE - o principal servio. Efetivamente, esse o
SGBD e consome bastante recursos do sistema.
TNSLISTERNER responsvel por fazer a comunicao entre as chamadas (consultas) ao B.D. e o servio do SGBD.
ISQLPLUS o servio que disponibiliza o programa iSQLPlus para realizar a conexo ao Oracle atravs de browser (11g).
Para localizar os servios, que na instalao so colocados para iniciar automaticamente, procure em: INICIAR / CONFIGURAES / PAINEL DE CONTROLE /
FERRAMENTAS ADMINISTRATIVAS / SERVIOS
7
-
http://:/isqlplus
http://ANDROMEDA:5560/isqlplusiSQLPlus
8
-
Criao de um usurio DBA
Para utilizar o Oracle, necessrio possuir um usurio (ou uma conta) atravs da qual possvel se conectar ao banco de dados.
Sintaxe:CREATE USER IDENTIFIED BY ;
Para se poder criar um usurio, preciso estar conectado com privilgio de administrador (SYSTEM).
CONN SYSTEM / ORACLE @ ORCL;
usurio senha banco
9
-
Criao de um usurio DBA (cont.)
Criando um usurio chamado wagner cuja senha unilins:CREATE USER wagner IDENTIFIED BY unilins;
Concedendo privilgio de Administrador (DBA) ao usurio:GRANT DBA TO wagner;
Conectando-se com o novo usurio:CONN WAGNER/UNILINS@ORCL;
Para verificar o usurio atual:SHOW USER;
Obs.: Por questo de segurana, no recomendado atribuir o privilgio de DBA para usurios comuns do sistemas.
10
-
Linguagem Procedural PL/SQL
A linguagem PL/SQL uma extenso do SQL Combina o poder de manipulao de dados do SQL com o
poder de processamento das linguagens de programao Estruturada em blocos Permite a criao de variveis Permite controle do fluxo de execuo (IF, FOR) Permite integrao entre diferentes ferramentas Oracle No permite comandos DDL No tem nenhuma funcionalidade de entrada ou de sada
construda diretamente na linguagem O PL/SQL no padronizado nos diversos SGBDs.
11
-
Vantagens do uso de PL/SQL
Possui maior poder de processamento (consultas e controle de fluxo)
Pode melhorar o desempenho de uma aplicao (reaproveita o mesmo plano de execuo)
Diminui o trafego de dados pela rede (vrias consultas pode ser encapsuladas numa nica requisio)
Controle centralizado no servidor (processamento centralizado)
Pode ser utilizado por diversas ferramentas (forms/reports, java, php, ...)
12
-
Bloco Annimo
So blocos PL/SQL que podem ser gerados para executar uma sequencia lgica de instrues SQL e procedurais.
Prottipo bsico:[DECLARE]
seo declarativa variveis, tipos, cursores e subprogramasBEGIN
seo executvel instrues SQL e procedurais[EXCEPTION]
seo de tratamento de exceesEND;
possvel, por exemplo, criar um bloco annimo para realizar a manuteno em algumas tabelas. Se esse bloco for salvo em arquivo SCRIPT, possvel carrega-lo e executa-lo todas as vezes que for necessrio.
13
-
Exemplo 01:Criando uma varivel e apresentado seu valor.
SET SERVEROUTPUT on;DECLARE N number := 5;BEGIN
dbms_output.put_line('Valor de N ' || N);END;
14
SERVEROUTPUT serve para habilitar a sada e fazer testes.
|| serve para concatenao
-
Exemplo 02:Criando uma varivel de substituio.
SET SERVEROUTPUT on;DECLARE S varchar2(20);BEGIN
S := '&input';dbms_output.put_line('Valor de S ' || S);
END;
15
&input uma varivel de substituio, usada para permitir que o usurio informe valores.
-
Exemplo 03:Tratando excees
SET SERVEROUTPUT on;DECLARE
S varchar2(10);BEGIN
S := '&input';dbms_output.put_line('Valor de S ' || S);
EXCEPTIONWHEN others THEN
dbms_output.put_line(SQLERRM);END;
16
Um possvel erro a digitao de uma string maior que o tamanho definido da varivel S.
-
Comentrios
H 2 tipos de comentrios em PL/SQL:
-- comentrio de uma nica linha.
/* comentrio de mltiplas linhas. em geral, usado para textos extensos. */
17
-
Estrutura de Controle Condicional
Estruturas de controle fazem a verificao de uma condio lgica e a ramificao da execuo de programas de acordo com as expresses booleanas.
Em PL/SQL, possvel criar desvios condicionais atravs de IF e CASE.
Todos statements IF so blocos e terminam com END IF. H 2 subtipos: if-then-else e if-then-elsif-then-else.
Os statements CASE tambm so blocos e terminam com END CASE.
A seguir, veremos exemplos do uso de IF e CASE.
18
-
IF, IF ... ELSE
BEGINIF 1=1 THEN
dbms_output.put_line('Equal');END IF;
END;
19
BEGINIF 1=2 THEN
dbms_output.put_line('Equal');ELSE
dbms_output.put_line('Different');END IF;
END;
-
IF ... ELSIF ... ELSE
20
BEGINIF 1>2 THEN
dbms_output.put_line('Major');ELSIF 1
-
Operadores Lgicos
BEGINIF 1=1 AND 2=2 THEN
dbms_output.put_line('True');END IF;
END;
21
BEGINIF 1=1 OR 1=2 THEN
dbms_output.put_line('True');END IF;
END;
-
Operadores Lgicos (cont.)
22
BEGINIF 1 BETWEEN 1 AND 3 THEN
dbms_output.put_line('In the range');END IF;
END;
BEGINIF 1 IN (1,2,3) THEN
dbms_output.put_line('In the set');END IF;
END;
-
Operadores Lgicos (cont.)
23
BEGINIF NOT FALSE THEN
dbms_output.put_line('True');END IF;
END;
BEGINIF 'Str%' LIKE 'String' THEN
dbms_output.put_line('Match');END IF;
END;
-
Operadores Lgicos (cont.)
24
DECLARE var BOOLEAN;BEGIN
IF var IS NULL THENdbms_output.put_line('It is null');
END IF;
END;
-
Exemplo 04:Calcular a mdia e verificar se foi aprovado.
DECLARE nota1 number := 8;nota2 number := 7;media number;
BEGINmedia:= (nota1+nota2) / 2;IF media >= 6.0 THEN
dbms_output.put_line('Voc foi aprovado!');ELSE
dbms_output.put_line('Voc foi reprovado');END IF;
END;
25
-
Exemplo 05:Comparar valores.
BEGINCASE true
WHEN (1>3) THENdbms_output.put_line('Um maior que trs');
WHEN (3
-
Estruturas Iterativas
O PL/SQL permite loops FOR, SIMPLE e WHILE. Loops FOR podem ser numricos e cursor.
O loop numrico repete atravs de um valor definido, enquanto loop cursor repete atravs de registros retornados por um cursor statement SELECT (veremos posteriormente).
Loops simples so estruturas explcitas. Eles exigem que voc gerencie ambos os ndice loop e o critrio exit.
O loop WHILE difere do loop simples, pois controla a entrada para o loop, no a sada.
Vermos a seguir os exemplos de estruturas iterativas.
27
-
Exemplo 06:Apresentar a tabuada do nmero 3 (FOR).
DECLARE N number := 3;R number;
BEGINFOR I IN 1..10 LOOP
R := N * I;
dbms_output.put_line(N || 'x' || I || ' = ' || R);END LOOP;
END;
28
-
Exemplo 07:Tabuada (LOOP simples).
DECLARE N number := 3;I number := 1;R number;
BEGINLOOP
EXIT WHEN I > 10;R := N * I;
dbms_output.put_line(N || 'x' || I || ' = ' || R);I := I + 1;
END LOOP;END;
29
-
Exemplo 08:Tabuada (WHILE).
DECLARE N number := 3;I number := 1;R number;
BEGINWHILE I
-
Uso de SQL em blocos annimos
Agora que j conhecemos as principais estruturas de controle da linguagem PL/SQL, iremos ver como usar em conjunto dos recursos SQL.
Assim, alm dos comando DML (SELECT, INSERT, UPDATE, DELETE), poderemos declarar variveis e usar instrues de controle (IF, CASE, FOR, LOOP, WHILE).
31
-
Exemplo 09:Obter a quantidade de registros de uma tabela.
CREATE TABLE tb_teste (codigo integer not null primary key,descricao varchar(40)
);
CREATE SEQUENCE seq_teste START WITH 1;
INSERT INTO tb_teste (codigo, descricao) VALUES (seq_teste.NEXTVAL, 'Teste 1');INSERT INTO tb_teste (codigo, descricao) VALUES (seq_teste.NEXTVAL, 'Teste 2');INSERT INTO tb_teste (codigo, descricao) VALUES (seq_teste.NEXTVAL, 'Teste 3');COMMIT;
32
DECLARE qtde number;BEGIN
SELECT count(*) INTO qtde FROM tb_teste;dbms_output.put_line(' Existem ' || qtde || ' registros.');
END;
-
Exemplo 10:Apresentar os registros de uma tabela.
BEGINFOR REG IN (SELECT descricao FROM tb_teste) LOOP
dbms_output.put_line(REG.descricao);END LOOP;
END;
33
A varivel REG instanciada automaticamente e o lao FOR executado de acordo com a quantidade de registros retornados pela consulta.
-
Exemplo 11:Inserir novos registros via PL/SQL.
BEGINFOR I IN 4..10 LOOP
INSERT INTO tb_teste (codigo, descricao) VALUES (seq_teste.NEXTVAL, 'Teste ' || I);
END LOOP;END;
34
ps. Executar o exemplo anterior para ver se os registros foram gravados.
-
Exemplo 12:Controle de transao.
BEGINSAVEPOINT init_transaction;FOR I IN 11..20 LOOP
INSERT INTO tb_teste (codigo, descricao) VALUES (seq_teste.NEXTVAL, 'Teste ' || I);
END LOOP;COMMIT;
EXCEPTIONWHEN others THEN
ROLLBACK TO init_transaction;dbms_output.put_line(SQLERRM);
END;
35
ps. Agora temos a garantia de que toda a transao seja realizada ou, caso ocorra algum erro durante a transao, toda a operao ser desfeita.
-
Exemplo 13:Excluir os registros com cdigos pares.
BEGINFOR REG IN (SELECT codigo FROM tb_teste) LOOP
IF MOD(REG.codigo, 2) = 0 thenDELETE FROM tb_teste WHERE REG.codigo = codigo;
END IF;
END LOOP;END;
36
ps. Utilize ROLLBACK para desfazer a excluso.lembre-se, o ROLLBACK s ir funcionar at o ltimo COMMIT.
-
Exemplo 14:Apresentar cdigo e descrio de todos os registros cadastrados. Ao final, apresentar a quantidade de registros listados. Caso a tabela esteja vazia,emitir uma mensagem de aviso.
BEGINSELECT count(*) INTO qtde FROM tb_teste;IF qtde > 0 then
FOR REG IN (select * from tb_teste) LOOPdbms_output.put_line(REG.codigo||' - '|| REG.descricao);
end LOOP;dbms_output.put_line('Listados: ' || qtde);
elsedbms_output.put_line('No h registros');
END IF;
END;
37
-
Exemplo 15:Apresentar em maisculo a descrio dos registros com cdigo at 5 e em minsculo a descrio dos registros com cdigo acima de 5.
38
BEGINFOR REG IN (select * from tb_teste) LOOP
IF REG.codigo
-
Exemplo 16:Apresentar todas as descries em minsculo, exceto a do registro com o maior cdigo de dever aparecer em maisculo.
39
DECLARE maior Number;
BEGINSELECT MAX(codigo) INTO maior FROM tb_teste;FOR REG IN (select * from tb_teste) LOOP
IF REG.codigo maior THENREG.descricao := lower(REG.descricao);
ELSEREG.descricao := upper(REG.descricao);
END IF;
dbms_output.put_line(REG.codigo||' - '|| REG.descricao);end LOOP;
END;
-
Exerccios1. Criar um bloco annimo que compare 2 nmeros e apresente o maior valor.2. Altere o exerccio anterior para que seja prevista a possibilidade dos valores
serem iguais.3. Altere o exerccio anterior para que seja prevista a possibilidade de existir valor
nulo.4. Criar um bloco annimo que dado o nmero de minutos retorne o nmero de
horas correspondente.5. Crie uma funo que dado um salrio retorne o nmero de salrios mnimos
que a pessoa ganha.6. Fazer um bloco annimo para verificar se o ano atual par.7. Fazer um bloco annimo para verificar se o ano atual bissexto.8. Criar um bloco annimo para apresentar os anos bissextos entre 2000 e 2100. 9. Escreva um bloco annimo que crie uma varivel do tipo date, atribua a data
corrente e mostre na tela: A data atual e o ltimo dia deste ms.10. Criar um bloco PL/SQL para imprimir os 15 primeiros termos da sequncia de
Fibonacci: 1 1 2 3 5 8 13 21 34 55 ...
40
-
1. Criar um bloco annimo que compare 2 nmeros e apresente o maior valor.
set serveroutput on;declare
n1 number := 3;n2 number := 5;
beginif (n1>n2) then
dbms_output.put_line(n1 || ' maior');else
dbms_output.put_line(n2 || ' maior');end if;
end;
41
-
2. Altere o exerccio anterior para que seja prevista a possibilidade dos valores serem iguais.
set serveroutput on;declare
n1 number := 3;n2 number := 5;
beginif (n1>n2) then
dbms_output.put_line(n1 || ' maior');elsif (n1
-
3. Altere o exerccio anterior para que seja prevista a possibilidade de existir valor nulo.
set serveroutput on;declare
n1 number := 3;n2 number := 5;
beginif (n1 is null) or (n2 is null) then
dbms_output.put_line('Valores invlidos!');elsif (n1>n2) then
dbms_output.put_line(n1 || ' maior');elsif (n1
-
4. Criar um bloco annimo que dado o nmero de minutos retorne o nmero de horas correspondente.
set serveroutput on;declare
M number := 120;H number;
beginH := M / 60;dbms_output.put_line(H);
end;
44
-
5. Crie uma funo que dado um salrio retorne o nmero de salrios mnimos que a pessoa ganha.
set serveroutput on;declare
minimo number := 622.00;salario number;qtde: number;
beginsalario := &salario;qtde := salario / minimo;dbms_output.put_line(qtde ' salrios mnimos');
end;
45
-
6. Fazer um bloco annimo para verificar se o ano atual par.
set serveroutput on;declare
ano number;begin
select extract(year from sysdate) into anofrom dual;if ano mod 2 = 0 then
dbms_output.put_line(ano || ' par');else
dbms_output.put_line(ano || ' mpar');end if;
end;
46
-
7. Fazer um bloco annimo para verificar se o ano atual bissexto.
set serveroutput on;declare
ano number;begin
select extract(year from sysdate) into anofrom dual;if ano mod 4 = 0 then
dbms_output.put_line(ano || ' bissexto');else
dbms_output.put_line(ano || ' no bissexto');end if;
end;
47
-
8. Criar um bloco annimo para apresentar os anos bissextos entre 2000 e 2100.
set serveroutput on;declare
ano number;begin
dbms_output.put_line('Anos bissextos entre 2000 e 2100');for ano in 2000..2100 loop
if ano mod 4 = 0 thendbms_output.put_line(ano);
end if;end loop;
end;
48
-
9. Escreva um bloco annimo que crie uma varivel do tipo date, atribua a data corrente e mostre na tela: A data atual e o ltimo dia deste ms.
set serveroutput on;declare
hoje date;ultimo date;
beginselect sysdate, last_day(sysdate) into hoje, ultimofrom dual;dbms_output.put_line(hoje || ' | ' || ultimo);
end;
49
-
10. Criar um bloco PL/SQL para imprimir os 15 primeiros termos da sequncia de Fibonacci: 1 1 2 3 5 8 13 21 34 55 ...
set serveroutput on;declare
ult number := 1;ant number := 0;aux number;
beginfor i in 1..15 loop
dbms_output.put_line(ult);aux := ult;ult := ult + ant;ant := aux;
end loop;end;
50
-
Cursores
Um cursor um tipo abstrato de dados da linguagem PL/SQL que permite armazenar o resultado de uma instruo SELECT. Ou seja, um cursor uma matriz gerada dinamicamente a partir de uma consulta.
Existem 2 tipos de cursores: explcitos e implcitos. Cursor explcito criado no bloco de declaraes. Cursor implcito criado dentro de qualquer bloco de
execuo ou de exceo.
Por questo de desempenho, o uso de cursores fortemente recomendado.
Sintaxe: declare cursor is ;
51
-
Criar as tabelas produto e categoria
create table tb_categoria (cod_cat integer not null primary key,descricao varchar(60)
);
create table tb_produto (cod_prod integer not null primary key,descricao varchar(60),preco decimal(8,2),cod_cat integer,foreign key(cod_cat) references tb_categoria(cod_cat)
);
52
-
Cadastrar alguns registroscreate sequence sq_produto start with 1 increment by 1;
insert into tb_categoria (cod_cat, descricao) values (1,'Informtica');
insert into tbl_categoria (cod_cat, descricao) values (2,'Papelaria');
insert into tb_produto (cod_prod,decricao,preco,cod_cat) values (sq_produto.nextval, 'Impressora', 250.00, 1);
insert into tb_produto (cod_prod, decricao,preco,cod_cat) values (sq_produto.nextval, 'mouse', 49.90, 1);
insert into tb_produto (cod_prod, decricao,preco,cod_cat) values (sq_produto.nextval, 'papel', 15.00, 2);
insert into tb_produto (cod_prod, decricao,preco,cod_cat) values (sq_produto.nextval, 'grampeador', 7.50, 2);
commit;
53
-
Cursor na forma expandida
Declare cursor C is select descricao, preco from tb_produto; R C%rowType;
BeginOpen C;Loop
Fetch C into R;Exit when C%NotFound;dbms_output.put_line(R.descricao || ' ' || R.preco);
End loop;Close C;
End;
54
No exemplo, o cursor foi declarado de forma explcita.
-
Cursor na forma simplificada
Declare cursor C is select descricao, preco from tb_produto;Begin
For R in C loopdbms_output.put_line(R.descricao || ' ' || R.preco);
End loop;End;
55
O cursor foi criado de forma implcita.No exemplo, o cursor aberto e fechado automaticamente.O lao de repetio tambm incrementado de forma automtica.
-
Apresentar a descrio do produto, preo do produto e a descrio da categoria.
Declare cursor C is select p.descricao, p.preco, c.descricao categoriafrom tb_produto p inner join tb_categoria c
on p.cod_cat = c.cod_cat;Begin
For R in C loopdbms_output.put_line(R.descricao || ' ' ||
R.preco || ' ' ||R.categoria);
End loop;End;
56
ps. Note que o cursor pode obter dados de uma ou mais tabelas.
-
Cursor recebendo parmetro
Apresentar uma listagem de cada categoria com seus respectivos produtos utilizando quebra de sesso por categoria. CATEGORIA HIGIENE:
- Sabonete R$ 0,80 - Shampoo R$ 4,20
CATEGORIA BEBIDA:
Coca-Cola R$ 4,50 Suco de uva R$ 7,80
57
-
Declare cursor CC is select cod_cat, descricaofrom tb_categoria;
cursor CP(p_cod_cat number) is select descricao, precofrom tb_produtowhere cod_cat = p_cod_cat;
BeginFor RC in CC loop
dbms_output.put_line('Categoria: ' || RC.descricao);For RP in CP(RC.cod_cat) loop
dbms_output.put_line('- ' || RP.descricao ||'R$ ' || RP.preco);
End loop;End loop;
End;
58
Cursor recebendo parmetro (cont.)
-
Stored Procedure
Um Stored Procedure um tipo de programa PL/SQL que, aps ser compilado, permanece armazenado no servidor do banco de dados, podendo ser executado a qualquer momento diretamente no banco ou atravs de uma linguagem de programao.
possvel criar Stored Procedures com ou sem parmetros formais. A execuo de uma stored procedure mais rpida do que a execuo
de instrues SQL simples. Sintaxe:
CREATE [OR REPLACE] PROCEDURE AS
BEGIN
END;
59
-
Exemplo 1:Stored Procedure para cadastrar novos produtos.
CREATE OR REPLACE procedure prc_inserir_produto(p_desc varchar, p_preco number) AS
BEGININSERT INTO tb_produto(cod_prod, descricao, preco)
VALUES(sq_produto.nextval, p_desc, p_preco);COMMIT;
END;
60
Para executar, use: EXEC prc_inserir_produto('iPad',1500.00);Em caso de erros: SHOW ERRORS;
-
Exemplo 2:Modificando o exemplo anterior para gravar a descrio em maisculo e sem espaos.
CREATE OR REPLACE procedure prc_inserir_produto(p_desc varchar, p_preco number) AS
BEGININSERT INTO tb_produto(cod_prod, descricao, preco)
VALUES(sq_produto.nextval, upper(trim(p_desc)),p_preco);
COMMIT;END;
61
-
Exemplo 3:Modificando o exemplo anterior para cadastrar somente valor positivo para o preo.
CREATE OR REPLACE procedure prc_inserir_produto(p_desc varchar, p_preco number) AS
v_preco number;BEGIN
if p_preco < 0 thenv_preco := p_preco * (-1);
elsev_preco := p_preco;
end if;INSERT INTO tb_produto(cod_prod, descricao, preco)
VALUES(sq_produto.nextval, p_desc, v_preco);COMMIT;
END;62
-
Passagem de Parmetro IN OUT
Existem 3 formas de passagem de parmetro em PL/SQL: IN, OUT e IN OUT. Com IN (forma default), o parmetro de entrada. Com OUT, a passagem por referncia.
create or replace procedure prc_par_impar(p_t IN number, p_ret OUT varchar2) is
beginif(MOD(p_t,2)=0) then
p_ret := ' par';else
p_ret := ' mpar';end if;
end;63
-
Exerccios (1/3)1. Criar um stored procedure que receba como parmetro o
cdigo de uma categoria e apresente todos os produtos desta categoria.
2. Modificar o programa anterior de forma que seja recebida a descrio da categoria ao invs do cdigo.
3. Elaborar um stored procedure que receba como parmetro a descrio de uma categoria e atualize os preos dos produtos. Os produtos com preo at 100 reais sero reajustados em 3%, os demais tero aumento de 5%.
4. Criar uma stored procedure para apresentar a descrio de cada categoria com a respectiva quantidade de produtos cadastrados.
5. Criar uma stored procedure para apresentar a descrio, o preo e a categoria do produto mais caro.
64
-
Exerccios (2/3)
6. Criar um stored procedure para receber a descrio de uma categoria e o percentual de aumento que dever ser aplicado a todos os produtos.
7. Criar um stored procedure para receber 2 cdigos de produtos. Deve-se aumentar em 8% o produto mais barato e baixar 6% o produto mais caro.
8. Criar um stored procedure para listar todos os produtos com quebra de sesso por categoria.
9. Criar um stored procedure para apagar as categorias que no possuem nenhum produto.
10. Criar um stored procedure para listar os produtos cadastrados em duplicidade (pela descrio).
65
-
Exerccios (3/3)11. Criar um stored procedure para listar os produtos at um
determinado preo. O valor do limite dever ser passado como parmetro.
12. Criar um stored procedure para listar os produtos cujo preo esteja dentro de um intervalo. Os limites do intervalo devero ser passados como parmetros.
13. Criar um stored procedure para listar as categorias com mais de 5 produtos.
14. Criar um stored procedure para listar todos os produtos com quebra de sesso por categoria, somente das categorias com mais de 5 produtos.
15. Criar um stored procedure que receba o cdigo de uma categoria e faa a excluso de seu registro, mas somente se a categoria no tiver produtos cadastrados.
66
-
1. Criar um stored procedure que receba como parmetro o cdigo de uma categoria e apresente todos os produtos desta categoria.
create or replace procedureprc_mostrar_produtos1(x number) AS
cursor p(y number) is select * from tb_produto where cod_cat = y;
beginfor r in p(x) loop
dbms_output.put_line('Descricao: '||r.descricao);dbms_output.put_line('Preco: ' || r.preco);
end loop;end;
exec prc_mostrar_produtos1(1);67
-
2. Modificar o programa anterior de forma que seja recebida a descrio da categoria ao invs do cdigo.
create or replace procedureprc_mostrar_produtos2(x varchar) AS
cursor p(y varchar) is select p.descricao, p.precofrom tb_produto p inner join tb_categoria c
on p.cod_cat = c.cod_catwhere c.descricao = y;
beginfor r in p(x) loop
dbms_output.put_line('Descricao: '||r.descricao);dbms_output.put_line('Preco: ' || r.preco);
end loop;end;
exec prc_mostrar_produtos2('Informtica');68
-
3. Elaborar um stored procedure que receba como parmetro a descrio de uma categoria e atualize os preos dos produtos. Os produtos com preo at 100 reais sero reajustados em 3%, os demais tero aumento de 5%.
create or replace procedureprc_atualizar_produtos(x varchar) as
v_cod_cat number;begin
select cod_cat into v_cod_catfrom tb_categoriawhere descricao = x;
update tb_produtoset preco = preco * 1.03where cod_cat = v_cod_cat and preco 100;
end;
exec prc_atualizar_produtos('Informtica');69
-
4. Criar uma stored procedure para apresentar a descrio de cada categoria com a respectiva quantidade de produtos cadastrados.
create or replace procedure prc_listar_categorias ascursor c is
select c.descricao, count(*) qtdefrom tb_categoria c inner join tb_produto p
on c.cod_cat = p.cod_catgroup by c.descricao;
beginfor r in c loop
dbms_output.put_line(r.descricao || ' - ' || r.qtde);end loop;
end;
70
-
5. Criar uma stored procedure para apresentar a descrio, o preo e a categoria do produto mais caro.
create or replace procedure prc_mais_caro asv_max number;cursor b(p_preco) is
select p.descricao, p.preco, c.descricao categoriafrom tb_categoria c left join tb_produto p
on c.cod_cat = p.cod_catwhere p.preco = p_preco;
beginselect MAX(preco) into v_max from tb_produto;for r in b loop
dbms_output.put_line(r.descricao || ' - ' ||r.preco || ' - ' ||r.categoria);
end loop;end;
exec prc_mais_caro;
71
-
6. Criar um stored procedure para receber a descrio de uma categoria e o percentual de aumento que dever ser aplicado a todos os produtos.
create or replace procedureprc_categoria_aumento(p_cat varchar, p_aumento number) as
beginupdate tb_produtoset preco = preco + (preco * p_aumento / 100)where cod_cat = (select cod_cat
from tb_categoriawhere descricao = p_cat);
end;
exec prc_categoria_aumento('Informtica', 3);
72
-
7. Criar um stored procedure para receber 2 cdigos de produtos. Deve-se aumentar em 8% o produto mais barato e baixar 6% o produto mais caro.
create or replace procedureprc_produto_aumento(p_cod1 number, p_cod2 number) as
preco1 number;preco2 number;
beginselect preco into preco1 from tb_produto where cod_prod = p_cod1;select preco into preco2 from tb_produto where cod_prod = p_cod2;if preco1
-
8. Criar um stored procedure para listar todos os produtos com quebra de sesso por categoria.
create or replace procedure prc_produtos_categoria ascursor a is
select cod_cat, descricao from tb_categoria;cursor b(p_cod_cat) is
select descricao, precofrom tb_produtowhere cod_cat = p_cod_cat;
beginfor c in a loop
dbms_output.put_line(c.descricao);for d in b(c.cod_cat) loop
dbms_output.put_line(d.descricao || ' ' || d.preco);end loop;
end loop;end;
exec prc_produtos_categoria;
74
-
9. Criar um stored procedure para apagar as categorias que no possuem nenhum produto.
create or replace procedure prc_categoria_vazia asbegin
delete from tb_categoriawhere cod_cat in
(select c.cod_catfrom tb_categoria c where not exists
(select 1 from tb_produto p where p.cod_cat=c.cod_cat));
end;
75
-
10. Criar um stored procedure para listar os produtos cadastrados em duplicidade (pela descrio).
create or replace procedure prc_produtos_duplicados ascursor a is
select descricao, count(*) qtdefrom tb_produtogroup by descricaohaving count(*) > 1;
begindbms_output.put_line('Produtos com descricao duplicada: '); for r in a loop
dbms_output.put_line(r.descricao || ' - ' || r.qtde);end loop;
end;
exec prc_produtos_duplicados;
76
-
11. Criar um stored procedure para listar os produtos at um determinado preo. O valor do limite dever ser passado como parmetro.
create or replace procedure prc_produto_preco(p_max number)ascursor a(p_maximo number) is
select descricao, precofrom tb_produtowhere preco
-
12. Criar um stored procedure para listar os produtos cujo preo esteja dentro de um intervalo. Os limites do intervalo devero ser passados como parmetros.
create or replace procedureprc_produto_faixa_preco(p_min number, p_max number)as
cursor a(p_minimo number, p_maximo number) is select descricao, precofrom tb_produtowhere preco between p_minimo and p_maximo;
beginfor r in a(p_min, p_max) loop
dbms_output.put_line(r.descricao || ' - ' || r.preco);end loop;
end;
exec prc_produto_faixa_preco(80,120);
78
-
13. Criar um stored procedure para listar as categorias com mais de 5 produtos.
create or replace procedure prc_listar_categorias ascursor c is
select c.descricao, count(*) qtdefrom tb_categoria c inner join tb_produto p
on c.cod_cat = p.cod_catgroup by c.descricaohaving count(*) > 5;
beginfor r in c loop
dbms_output.put_line(r.descricao || ' - ' || r.qtde);end loop;
end;
79
-
14. Criar um stored procedure para listar todos os produtos com quebra de sesso por categoria, somente das categorias com mais de 5 produtos.
create or replace procedure prc_produtos_categoria_5 ascursor a is
select c.cod_cat, c.descricao, count(*) qtdefrom tb_categoria c inner join tb_produto p
on c.cod_cat = p.cod_catgroup by c.cod_cat, c.descricaohaving count(*) > 5;
cursor b(p_cod_cat number) isselect descricao, precofrom tb_produtowhere cod_cat = p_cod_cat;
beginfor c in a loop
dbms_output.put_line(c.descricao);for d in b(c.cod_cat) loop
dbms_output.put_line(d.descricao || ' ' d.preco);end loop;
end loop;end;
80
-
15. Criar um stored procedure que receba o cdigo de uma categoria e faa a excluso de seu registro, mas somente se a categoria no tiver produtos cadastrados.
create or replace procedureprc_excluir_categoria(p_cod_cat number) as
v_qtde number;cursor a is
select COUNT(*) into v_qtdefrom tb_produtowhere cod_cat = p_cod_cat;
beginif v_qtde = 0 then
delete from tb_categoria where cod_cat = p_cod_cat;dbms_output.put_line('Excluso realizada');
elsedbms_output.put_line('Excluso no realizada');
end if;end;
exec prc_excluir_categoria(1);
81
-
Tipos de Exceo
Os erros de programas PL/SQL ocorrem quando voc comete um erro digitando o programa ou definindo o programa. Erros de compilao Erros de execuo (run-time)
82
-
Erros de compilao
So geralmente erros de digitao: Esquecer um ponto e vrgula No fechar uma string literal Escrever de maneira errada um identificador
(palavra reservada) Comentar um valor lxico requerido pelas regras de
anlise
comum que um erro de compilao seja acusado na linha seguinte em que tenha ocorrido.
83
-
Erros de execuo (run-time)
Erros de run-time podem ocorrer na declarao, execuo e blocos de exceo PL/SQL.
Erros levantados no bloco de execuo so lanados no bloco de exceo local.
84
Funo Erros pr-definidos pelo Oracle
Erros definidos pelo usurio
SQLCODE Retorna um nmero negativo que mapeia as excees pr-definidas do Oracle.
Retorna um 1 positivo se no existeEXCEPTION_INIT PRAGMA definida. Se estiver definida, retorna um nmero negativo entre -20001 e -20999.
SQLERRM Retorna o cdigo de erro e mensagem para uma exceo.
Retorna um 1 e uma mensagem definida pelo usurio se disparada pelo comando RAISE. Caso contrrio, retorna um cdigo de erro entre -20001 e -20999 e uma mensagem de texto ajustada por RAISE_APPLICATION_INFO.
-
Funes Pr-definidas de Excees (1/2)
85
EXCEO ERRO QUANDO OCORREACCESS_INTO_NULL ORA-06530 Ocorre ao tentar acessar um objeto no inicializado.CASE_NOT_FOUND ORA-06592 Ocorre quando um statement CASE criado sem uma
clusula ELSE e nenhuma condio executada.CURSOR_ALREADY_OPEN ORA-06531 Ocorre ao tentar abrir um cursor que j est aberto.DUP_VAL_ON_INDEX ORA-00001 Ocorre ao tentar inserir um valor duplicado de ndice.
INVALID_CURSOR ORA-01001 Ocorre ao tentar uma operao no permitida sobre um cursor, como fechar um cursor fechado.
INVALID_NUMBER ORA-01722 Ocorre ao tentar atribuir algo no numrico para um campo numrico.
LOGIN_DENIED ORA-01017 Ocorre ao tentar entrar em um programa com um nome de usurio ou senha invlida.
NO_DATA_FOUND ORA-01403 Ocorre ao tentar usar a estrutura SELECT-INTO e o statement retornar um valor nulo.
NOT_LOGGED_ON ORA-01012 Ocorre quando um programa lanar uma chamada de banco de dados e no estiver conectado, por exemplo aps ter desconectado sua sesso.
-
Funes Pr-definidas de Excees (2/2)
86
EXCEO ERRO QUANDO OCORREPROGRAM_ERROR ORA-06501 Ocorre quando o Oracle no tenha pego formalmente o
erro ocorrido.ROWTYPE_MISMATCH ORA-06504 Ocorre quando sua estrutura de cursor falhar ao
concordar com sua varivel cursor ou parmetro formalSTORAGE_ERROR ORA-06500 Esse erro ocorre quando o SGA ficar sem memria ou
estiver corrompido.SYS_INVALID_ROWID ORA-01410 Ocorre ao tentar converter uma string em um valor
ROWID invlido.TIMEOUT_ON_RESOURCE ORA-00051 Ocorre quando o BD no for capaz de assegurar um
bloqueio a um recurso.TOO_MANY_ROWS ORA-01422 Ocorre ao usar o SELECT-INTO ou sub-query e a
consulta retornar mais de uma linha. VALUE_ERROR ORA-0650 Isso ocorre ao tentar atribuir uma varivel dentro de
outra que muito pequena para sustent-la.ZERO_DIVIDE ORA-01476 Isso ocorre ao tentar dividir um nmero por zero.
-
Diretrizes para a Captura de Excees
A palavra-chave EXCEPTION inicia a seo de tratamento de excees.
WHEN OTHERS a ltima clusula.
So permitidos vrios handlers de exceo.
Somente um handler processado antes de se sair do bloco.
permitido o uso de operadores lgicos (AND, OR, NOT)
87
-
Exemplo 1Consultar preo de um produto.
DECLAREv_descricao tb_produto.descricao%type := '&p_descricao';v_preco tb_produto.preco%type;
BEGINSELECT preco INTO v_precoFROM tb_produtoWHERE descricao = v_descricao;dbms_output.put_line('Preo: ' || v_preco);
EXCEPTIONWHEN NO_DATA_FOUND THEN
dbms_output.put_line('NENHUM REGISTRO ENCONTRADO.');WHEN TOO_MANY_ROWS THEN
dbms_output.put_line('PRODUTOS COM MESMA DESCRIO.');WHEN OTHERS THEN
dbms_output.put_line('ERRO DESCONHECIDO.' );END;
88
-
Usando Stored Procedure com parmetro OUT
CREATE OR REPLACE PROCEDURE prc_buscaProduto(p_codigo IN number, p_descricao OUT varchar2, p_preco OUT number) is
BEGINSELECT descricao, precoINTO p_escricao, p_precoFROM tb_produtoWHERE cod_prod = p_codigo;
EXCEPTIONWHEN NO_DATA_FOUND THEN
p_descricao := 'Produto no localizado';p_preco := 0;
END;89
-
DECLAREv_codigo tb_produto.cod_prod%TYPE; v_descricao tb_produto.descricao%TYPE;v_preco tb_produto.preco%TYPE;
BEGINv_codigo := 12;prc_buscaProduto(v_codigo, v_descricao, v_preco);dbms_output.put_line('Cdigo: ' || v_codigo);dbms_output.put_line('Descrio: ' || v_descricao);dbms_output.put_line('Preo: ' || v_preco);
END;
90
Usando Stored Procedure com parmetro OUT (cont.)
-
Exemplo 2Chave primria duplicada.
DECLAREv_descricao tb_produto.descricao%TYPE;v_preco tb_produto.preco%TYPE;v_cod_cat tb_produto.cod_cat%TYPE;
BEGINv_descricao := 'Pen drive'; v_preco := 44.99; v_cod_cat := 1;INSERT INTO tb_produtoVALUES(1, v_descricao, v_preco, v_cod_cat);dbms_output.put_line ('Insero executada com sucesso.');
EXCEPTIONWHEN DUP_VAL_ON_INDEX THEN
dbms_output.put_line ('Cdigo j cadastrado.' );WHEN Others THEN
dbms_output.put_line ('Erro no cadastramento.' );END;
91
-
Exemplo 3Valor muito grande para o campo.
DECLAREv_descricao VARCHAR(10);v_preco number(3,2);
BEGINv_descricao := 'Pen drive de 128GB e USB3'; v_preco := 144.99; dbms_output.put_line ('Descrio: ' || v_descricao);dbms_output.put_line ('Preo: ' || v_preco);
EXCEPTIONWHEN VALUE_ERROR THEN
dbms_output.put_line (SQLERRM);WHEN Others THEN
dbms_output.put_line (SQLERRM);END;
92
-
Exemplo 4Valor numrico invlido.
DECLAREv_descricao VARCHAR(10);v_preco number(3,2);
BEGINv_descricao := 'Pen drive'; v_preco := 'A49.99'; dbms_output.put_line ('Descrio: ' || v_descricao);dbms_output.put_line ('Preo: ' || v_preco);
EXCEPTIONWHEN INVALID_NUMBER THEN
dbms_output.put_line ('Valor numrico invlido');WHEN Others THEN
dbms_output.put_line (SQLERRM);END;
93
-
Exemplo 5Diviso por ZERO.
DECLAREvalor number(8,2);
BEGINvalor := 100 / 0;dbms_output.put_line ('Resultado: ' || valor);
EXCEPTIONWHEN ZERO_DIVIDE THEN
dbms_output.put_line (SQLERRM);WHEN Others THEN
dbms_output.put_line (SQLERRM);END;
94
-
Possvel gravar os erros ocorridosDECLARE v_code number;
v_erro varchar(100);BEGIN...EXCEPTION...
WHEN OTHERS THENROLLBACK;v_code := SQLCODE;v_erro := SQLERRM;INSERT INTO tb_errosVALUES(v_code, v_erro);
END;
Obs. preciso criar a tabela de erros.create table tb_erros (
codigo_erro number, mensagem_erro varchar2(100)
);95
-
Declarando excees do usurio
Uma exceo declarada como qualquer outra varivel PL/SQL.
DECLARE e EXCEPTION;
BEGINRAISE e;dbms_output.put_line('Essa linha no ser executada');
EXCEPTIONWHEN OTHERS THENIF SQLCODE = 1 THEN
dbms_output.put_line('SQLERRM');END IF;
END;
Resposta: [User-Defined Exception]
96
-
Exemplo 1Alterar um produto
DECLAREe_invalid_product EXCEPTION;
BEGINUPDATE tb_produtoSET descricao = '&product_description' WHERE cod_prod = &product_number;
IF SQL%NOTFOUND THENRAISE e_invalid_product;
END IF;
COMMIT;EXCEPTION
WHEN e_invalid_product THEN DBMS_OUTPUT.PUT_LINE('Cdigo de produto invlido.');
END;
97
-
Exemplo 2Cadastrar Categoria
DECLAREv_codigo tb_categoria.cod_cat%Type;v_descricao tb_categoria%Type;campos_obrigatorios EXCEPTION;
BEGIN-- v_codigo := 1;
v_descricao := 'Material Esportivo';IF (codigo IS NULL) OR (descricao IS NULL) THEN
RAISE campos_obrigatorios;ELSE
INSERT INTO tb_categoria(cod_cat, descricao) VALUES (v_codigo, v_descricao);END IF;
EXCEPTIONWHEN campos_obrigatorios THEN
dbms_output.put_line ('Preencher todos os campos.');WHEN Dup_Val_On_Index THEN
dbms_output.put_line ('Cdigo j cadastrado.' );WHEN Others THEN
dbms_output.put_line ('Erro no cadastramento.' );END;
98
-
PRAGMA EXECEPTION_INIT
O PRAGMA EXCEPTION_INIT associa um nome de exceo a um nmero de erro do Oracle. Capturar erro -2292, violao de restrio de integridade.
DECLARE e_categoria EXCEPTION;PRAGMA EXCEPTION_INIT (e_categoria, -2292);v_cod_cat tb_categoria.cod_cat%TYPE := &p_cod_cat;
BEGINDELETE FROM tb_categoria WHERE cod_cat = v_cod_cat;COMMIT;
EXCEPTION WHEN e_categoria THEN
DBMS_OUTPUT.PUT_LINE('Categoria no pode ser removida. Existem produtos relacionados.');
END;
99
-
RAISE_APPLICATION_ERROR
O RAISE_APPLICATION_ERROR aborta a execuo.
DECLAREsem_comissao EXCEPTION; -declara uma exception
BEGINIF comissao IS NULL THEN
RAISE sem_comissao; -chama a exceptionEND IF;
bonus := (salario * 0.10) + (comissao * 0.15);EXCEPTION
WHEN sem_comissao THENRAISE_APPLICATION_ERROR(-21000,No h comisso!);
END;
100
-
Exerccios
1. Criar um bloco annimo que receba como parmetro o cdigo de um produto e o percentual de aumento. Deve-se atualizar o preo do produto. Caso o cdigo informado no exista ou o preo atual seja nulo, deve-se gerar uma exceo.
2. Alterar o exerccio anterior trabalhando com stored procedure.3. Criar um stored procedure que receba o cdigo de um produto a ser
excludo. Caso o produto no exista, gerar uma exceo.4. Criar um stored procedure que receba a descrio, preo e categoria
de um produto. Verificar:a) Se todos os campos foram preenchidosb) Se o tamanho do campo descrio compatvel.c) Se o tipo do campo preo vlido.d) Se a categoria informada existe.e) Se outro erro ocorrer, apresentar o cdigo e a descrio do erro.
101
-
102
Trabalho (individual ou em dupla)Sistema para cotao de preos (1/3)
O diagrama de classes acima representa um sistema para cotao de preos, no qual: cada cotao possui um produto; cada cotao recebe propostas de diversos fornecedores; cada fornecedor poder enviar proposta para uma ou mais cotaes.
COTACAOcod_cotqtdedata_iniciodata_terminoPROPOSTA
valorprazo_entrega
0..N 0..NFORNECEDORcod_fornrazao_socialnome_fantasiacnpjieenderecocidadetelefone
PRODUTOcod_proddescricaoprecoestoque
0..N1..1
-
Trabalho:Sistema para cotao de preos (2/3)
1. Criar um bloco annimo para listas os fornecedores cadastrados.
2. Criar um bloco annimo para listas todas as cotaes cadastradas (com descrio do produto, qtde e perodo)
3. Criar um bloco annimo para listas as cotaes em aberto (com descrio do produto, qtde cotada e perodo).
4. Criar um bloco annimo que apresente a relao de produtos com as respectivas cotaes j realizadas.
5. Criar um stored procedure para cadastrar novos fornecedores. O cdigo do fornecedor dever ser gerado automaticamente e deve-se verificar se o cnpj j est cadastrado.
103
-
Trabalho:Sistema para cotao de preos (3/3)
6. Criar um stored procedure que receba o cdigo de uma cotao e apresente as propostas recebidas (valor, prazo, razo social e cnpj do fornecedor)
7. Criar uma stored procedure que receba o cdigo de um produto e apresente as cotaes j realizadas.
8. Criar um stored procedure que receba o cnpj de um fornecedor e apresente as proposta feitas (valor, prazo, produto e qtde)
9. Criar um stored procedure que receba como parmetro uma data e apresente todas as cotaes ativas nesta data.
10. Criar um stored procedure que apresente as cotaes encerradas, abertas ou ainda aguardando incio. Deve-se passar como parmetro qual filtro dever ser aplicado.
104
-
Function (funo) Uma funo um programa PL/SQL que sempre
retorna um valor aps sua execuo. Assim como em Stored Procedure, podemos passar parmetros para uma funo. A diferena que as funes so chamadas como parte de uma expresso.
Sintaxe: CREATE [OR REPLACE] FUNCTION
[ ( ) ] RETURN IS
: ;BEGIN
;RETURN ;
END;
105
-
Como executar uma funo:
Com chamada: CALL function_name(parameter)
INTO target_variable_name;
Dentro de blocos PL/SQL: target_variable_name := function_name(parameter);
Com SQL: SELECT function_name(parameter)
FROM table_name;
Obs.: caso a funo no tenha parmetro, basta omitir.
106
-
Exemplo 1: Funo que recebe um valor e retorna o seu quadrado.
CREATE FUNCTION fn_quadrado(n IN number) RETURN number IS
q number;BEGIN
q := n * n;RETURN q;
END;
Para executar: SELECT fn_quadrado(5) FROM dual;
107
-
Exemplo 2: Funo que retorne o dia de amanh.
CREATE OR REPLACE FUNCTION fn_amanhaRETURN date ISd date;BEGIN
SELECT SYSDATE+1 INTO d FROM DUAL;RETURN d;
END;
Para executar: SELECT fn_amanha FROM dual;
108
-
Exemplo 3: Retornar a mdia de preos dos produtos.
CREATE OR REPLACE FUNCTION fn_media_precosRETURN number ISmedia number;BEGIN
SELECT AVG(preco) INTO media FROM tb_produto;
RETURN media;END;
Para executar: SELECT fn_media_precos FROM dual;
109
-
Exemplo 4: Recebe preo do produto e percentual de desconto, retorna o valor da promoo.
CREATE OR REPLACE FUNCTION fn_promocao(preco number, percentual number)
RETURN number ISBEGIN
RETURN preco - (preco * percentual / 100);END;
Teste 1: SELECT fn_promocao(100, 5) FROM dual;
Teste 2: SELECT descricao, preco, fn_promocao(preco, 5) promocaoFROM tb_produto;
obs.: a funo executada para cada registro encontrado na tabela tb_produto.
110
-
Exemplo 5: Calcular desconto de 3% se o preo custar at 100 reais, de 5% para at 1000 reais e de 8% se for acima de 1000 reais.
CREATE OR REPLACE FUNCTION fn_promocao(preco number) RETURN number ISpromocao number;BEGIN
if preco
-
Exerccios1. Crie uma funo que receba um nmero e retorne seu valor fatorial. 3! = 1x2x32. Criar uma funo que receba um nome completo e retorne apenas o primeiro
nome.
3. Crie uma funo que receba o nmero do ms e retorne o nome deste.4. Crie uma funo que receba como parmetro uma data (dia, ms e ano) e
retorne a data por extenso. Exemplo: 12/03/2008 12 de maro de 20085. Criar uma funo que receba uma data e retorne a idade em anos.6. Criar uma funo para recuperar o nmero de horas e minutos entre duas
datas.7. Criar uma funo que receba um CPF e retorne se vlido. 8. Criar uma funo que receba como parmetro o valor inicial e o valor final e
retorne a quantidade de produtos com preo dentro do intervalo.9. Criar uma funo que receba a descrio de um produto e retorne se o produto
est cadastrado ou no.10. Criar uma funo receber o preo de um produto e o classificar como baixo,
mdio ou alto, respectivamente para valores at 100, acima de 100 at 1000 e acima de 1000.
112
-
1. Criar uma funo que receba um nmero e retorne seu fatorial.
create or replace FUNCTION fatorial(n IN number) RETURN number IS
f number := 1;
BEGINFOR i IN 1..n LOOP
f := f * i;END LOOP;
RETURN f;END;
SELECT fatorial(5) FROM dual;
113
-
2. Criar uma funo que receba um nome completo e retorne apenas o primeiro nome.
CREATE OR REPLACE FUNCTION primeiro_nome(p_nome varchar)RETURN varchar ISv_nome varchar(80);v_posicao number;BEGIN
v_posicao := instr(ltrim(p_nome),' ');if v_posicao = 0 then
v_nome := p_nome;else
v_nome := substr(ltrim(p_nome), 1, v_posicao-1);end if;return v_nome;
END;
SELECT nome, primeiro_nome(nome) FROM tb_funcionario;114
-
3. Crie uma funo que receba o nmero do ms e retorne o nome deste.
CREATE OR REPLACE FUNCTION fn_mes_extenso(p_mes number) RETURN varchar ISv_mes varchar(30);
BEGINCASE
WHEN p_mes= 1 THEN v_mes := 'Janeiro';WHEN p_mes= 2 THEN v_mes := 'Fevereiro';WHEN p_mes= 3 THEN v_mes := 'Maro';WHEN p_mes= 4 THEN v_mes := 'Abril';WHEN p_mes= 5 THEN v_mes := 'Maio';WHEN p_mes= 6 THEN v_mes := 'Junho';WHEN p_mes= 7 THEN v_mes := 'Julho';WHEN p_mes= 8 THEN v_mes := 'Agosto';WHEN p_mes= 9 THEN v_mes := 'Setembro';WHEN p_mes=10 THEN v_mes := 'Outubro';WHEN p_mes=11 THEN v_mes := 'Novembro';WHEN p_mes=12 THEN v_mes := 'Dezembro';ELSE v_mes := 'Invlido!';
END CASE;RETURN v_mes;
END;
SELECT fn_mes_extenso(8) FROM dual; --Agosto115
-
4. Crie uma funo que receba como parmetro uma data (dia, ms e ano) e retorne a data por extenso. Exemplo: 12/03/2008 12 de maro de 2008.
CREATE OR REPLACE FUNCTION fn_data_extenso(p_data date)RETURN varchar ISBEGIN
RETURN to_char(p_data, 'DD de MONTH de YYYY','nls_date_language=portuguese');
END;
SELECT fn_data_extenso(SYSDATE) FROM dual;
116
-- maneira de separar a data-- v_dia := EXTRACT(DAY FROM p_data);-- v_mes := EXTRACT(MONTH FROM p_data);-- v_ano := EXTRACT(YEAR FROM p_data);
-
5. Criar uma funo que receba uma data e retorne a idade em anos.
CREATE OR REPLACE FUNCTION fn_idade(p_data date)RETURN number ISv_idade number;BEGIN
SELECT floor(months_between(SYSDATE, p_data) / 12) INTO v_idadeFROM dual;
RETURN v_idade;END;
SELECT fn_idade('01/05/2010') FROM dual;
117
-
6. Criar uma funo para recuperar o nmero de horas e minutos entre duas datas. (1/2)
CREATE OR REPLACE FUNCTION fn_diferenca_datas(p_inicial date, p_final date) IS
RETURN varchar;
diferenca number;horas number;minutos number;
BEGIN
SELECT p_final-p_inicial INTO diferenca FROM dual;SELECT trunc(diferenca)*24 + trunc((diferenca - trunc(diferenca))*24),
trunc((((diferenca - trunc(diferenca))*24) trunc((diferenca - trunc(diferenca))*24))*60)
INTO horas, minutosFROM dual;RETURN horas || 'h' || minutos || 'm';
END;
118
-
6. Criar uma funo para recuperar o nmero de horas e minutos entre duas datas. (2/2)
Exemplo de uso: DECLARE
data_inicial date;data_final date;resposta varchar(20);
BEGINdata_inicial := to_date('21/11/2010 18:57:00','dd/mm/yyyy hh24:mi:ss');data_final := to_date('22/11/2010 21:40:25','dd/mm/yyyy hh24:mi:ss');resposta := fn_diferenca_datas(data_inicial, data_final);dbms_output.put_line(resposta);
END;
119
-
7. Criar uma funo que receba um CPF e retorne se vlido. (1/2)
CREATE OR REPLACE FUNCTION fn_valida_cpf (p_cpf IN CHAR) RETURN BOOLEAN IS
m_total NUMBER := 0;m_digito NUMBER := 0;
BEGINFOR i IN 1 .. 9 LOOP
m_total := m_total + SUBSTR (p_cpf, i, 1) * (11 - i);END LOOP;
m_digito := 11 - MOD (m_total, 11);
IF m_digito > 9 THENm_digito := 0;
END IF;
IF m_digito != SUBSTR (p_cpf, 10, 1) THENRETURN FALSE;
END IF;
120
-
7. Criar uma funo que receba um CPF e retorne se vlido. (2/2)
m_digito := 0;m_total := 0;
FOR i IN 1 .. 10 LOOPm_total := m_total + SUBSTR (p_cpf, i, 1) * (12 - i);
END LOOP;
m_digito := 11 - MOD (m_total, 11);
IF m_digito > 9 THENm_digito := 0;
END IF;
IF m_digito != SUBSTR (p_cpf, 11, 1) THENRETURN FALSE;
END IF;
RETURN TRUE;END;
121
-
8. Criar uma funo que receba como parmetro o valor inicial e o valor final e retorne a quantidade de produtos com preo dentro do intervalo.
CREATE OR REPLACE FUNCTION fn_qtde_produtos(p_inicial NUMBER, p_final NUMBER)
RETURN number ISv_qtde number;
BEGINSELECT COUNT(*) INTO v_qtdeFROM tb_produtoWHERE preco BETWEEN p_inicial AND p_final;
RETURN v_qtde;END;
Exemplo de uso:DECLARE
v_qtde number(10);BEGIN
v_qtde := fn_qtde_produtos(50,80);dbms_output.put_line(v_qtde || ' produtos encontrados!');
END;
122
-
9. Criar uma funo que receba a descrio de um produto e retorne se o produto est cadastrado ou no.
CREATE OR REPLACE FUNCTION fn_procurar(p_descricao IN varchar) RETURN boolean IS
v_qtde number;BEGIN
SELECT COUNT(*) INTO v_qtdeFROM tb_produtoWHERE descricao = p_descricao;
RETURN (v_qtde0);END;
Exemplo de uso:DECLARE
v_descricao varchar(100) := 'Mouse';BEGIN
IF(fn_procurar(v_descricao)) THENdbms_output.put_line('Produto no encontrado!');
ELSEdbms_output.put_line('Produto encontrado!');
END IF;END;
123
-
10. Receber o preo de um produto e o classificar como baixo, mdio ou alto, respectivamente para valores at 100, acima de 100 at 1000 e acima de 1000.
CREATE OR REPLACE FUNCTION fn_classificar(p_preco IN number) RETURN varchar ISBEGIN
IF p_preco
-
Package (Pacote)
125
Package so reas de armazenamentos de subprogramas (stored procedure e function), constantes, variveis e cursores em PL/SQL que podero ser compartilhados com outros aplicativos.
Em outras palavras, os pacotes funcionam como bibliotecas do PL/SQL.
Existem packages nativos do Oracle e possvel criar novos pacotes.
Um PACKAGE constitudo de duas partes: PACKAGE SPECIFICATION PACKAGE BODY
-
Partes do Package
PACKAGE SPECIFICATION Tem como funo de criar a interface (prottipo) de suas
aplicaes e definir os tipos de variveis, cursores, excees, nomear rotinas, e funes, tudo que se define na parte de SPECIFICATION do seu PACKAGE poder ser compartilhado com outros scripts ou programasem SQL e PL/SQL.
PACKAGE BODY Tem como funo executar por completo todas as suas
rotinas, cursores e etc., que voc definiu na SPECIFICATION. Alm disso no BODY voc poder criar detalhes e declaraes que ficaro invisveis para outras aplicaes.
126
-
Partes do Package: visibilidade
127
-
Especificao do Pacote
CREATE OR REPLACE PACKAGE pkg_comissao IScomissao_padrao NUMBER := 0.10;PROCEDURE mudar_comissao(nova_comissao NUMBER);
END pkg_commissao;
128
comissao_padrao uma varivel global inicializada com 0.10 (10%).
mudar_comissao um procedimento pblico usado para redefinir a comisso fixa com base em algumas regras de negcio. Ele implementado no corpo do pacote.
-
Corpo do Pacote
CREATE OR REPLACE PACKAGE BODY pkg_comissao ISfunction fn_validar(comissao number) RETURN boolean ISmax_comissao tb_vendedor.comissao%TYPE;begin
select max(comissao) into max_comissao from tb_vendedor;RETURN (comissao BETWEEN 0.0 AND max_comissao);
end fn_validar;procedure prc_mudar_comissao(nova_comissao number) ISbegin
if fn_validar(nova_comissao) thencomissao_padrao := nova_comissao;
elseraise_application_error(-20210, 'Comisso Invlida!');
end if;end prc_mudar_comissao;
END pkg_comissao;
129
-
Utilizando o pacote: Chamando um procedimento a partir do SQL*Plus:
EXEC pkg_comissao.mudar_comissao(0.15);
Chamando uma procedimento em um esquema diferente: EXEC scott.pkg_comissao.mudar_comissao(0.15);
Para remover a especificao do pacote e do corpo: DROP PACKAGE pkg_comissao;
Para remover somente o corpo do pacote: DROP PACKAGE BODY pkg_comissao;
Para ver a especificao do pacote no dicionrio de dados: SELECT text FROM user_source
WHERE name = 'PKG_COMISSAO' AND type = 'PACKAGE';
Para ver o corpo do pacote: SELECT text FROM user_source
WHERE name = 'PKG_COMISSAO' AND type = 'PACKAGE BODY';
130
-
Orientaes para Escrita de Pacotes
Construa pacotes para uso geral.
Defina a especificao do pacote antes do corpo. A especificao do pacote deve conter apenas as
construes que voc quer que seja pblico. Mudanas nas especificaes do pacote requer
recompilao de cada subprograma referncia. A especificao do pacote deve conter o mnimo de
construes possvel.
131
-
Vantagens no Uso de Pacotes Facilita a manuteno:
Mantm a funcionalidade e a lgica juntas
Design fcil: Codificao da especificao e do corpo separadamente
Esconde informaes: Somente as declaraes na especificao do pacote so visveis e
acessveis para as aplicaes.
Construes no corpo do pacote esto privadas e inacessveis.
Funcionalidades adicionais: cursores
Melhor desempenho: O pacote inteiro carregado na memria naprimeira vez que for
referenciado.
Existe apenas uma cpia na memria para todos os usurios.
Sobrecarga: mltiplos subprogramas com o mesmo nome
132
-
Exerccios
1. Criar uma package chamado pkg_math com a seguinte estrutura:a) Uma varivel global PI com o valor 3.14159265b) Uma funo que receba como parmetro o raio, calcule e
retorne a rea de um crculo (pi * r2)c) Uma funo que receba como parmetro o raio e a altura
de um cilindro, calcule e retorne seu volume (pi * r2 * h)d) Um stored procedure para calcular o volume de uma esfera
(4/3 * pi * r3). Deve-se passar 2 parmetros: o primeiro parmetro (tipo IN) com o valor do raio da esfera e o segundo parmetro (tipo OUT) receber o volume calculado.
133
-
Exerccio 1 - Soluo create or replace package pkg_math is
PI number := 3.14159265;function fn_area_circulo(raio number) return number;function fn_volume_cilindro(raio number, altura number) return number;procedure prc_volume_esfera(raio IN number, volume OUT number);
end;
create or replace package body pkg_math isfunction fn_area_circulo(raio number) return number isbegin
return PI * (raio*raio);end;function fn_volume_cilindro(raio number, altura number) return number isbegin
return PI * (raio*raio) * altura;end;procedure prc_volume_esfera(raio IN number, volume OUT number) isbegin
volume := 4/3 * PI * (raio*raio*raio);end;
end;
134
-
Exerccio 1 Soluo (cont.)
Declarer number := 10;a number := 20;x number;
Beginx := pkg_math.fn_area_circulo(r);dbms_output.put_line('Um circulo de raio ' || r || ' tem rea ' || x);
x := pkg_math.fn_volume_cilindro(r, a);dbms_output.put_line('Um cilindro de raio ' || r || ' e altura ' || a || ' tem volume ' || x);
pkg_math.prc_volume_esfera(r, x);dbms_output.put_line('Uma esfera de raio ' || r || ' tem volume ' || x);
End;
135
-
Exerccios
2. Criar uma package chamado pkg_date com a seguinte estrutura:a) Um campo privado chamado idioma com o valor inicial
'portuguese'b) Uma funo que receba como parmetro o novo idioma,
que pode ser portuguese, english ou spanish, e altere a varivel global idioma.
c) Uma funo que retorne o valor do idioma atual.d) Um stored procedure para obter a data por extenso. Deve-
se passar 2 parmetros: o primeiro parmetro (tipo IN) com uma data no formato dd/mm/yyyy e o segundo parmetro (tipo OUT) receber a data por extenso no idioma atual.
136
-
Exerccio 2 - Soluo create or replace package pkg_date is
function fn_set_idioma(i varchar) return boolean;function fn_get_idioma return varchar;procedure prc_get_date(d IN date, extenso OUT varchar);
end;
create or replace package body pkg_date isidioma varchar(30) := 'portuguese';function fn_set_idioma(p_idioma varchar) return boolean isbegin
if(p_idioma in('portuguese','spanish','english')) thenidioma := p_idioma;return true;
elsereturn false;
end if;end;function fn_get_idioma return varchar isbegin
return idioma;end;procedure prc_get_date(d IN date, extenso OUT varchar) isbegin
extenso := to_char(d,'DD/MONTH/YYYY', 'nls_date_language='||idioma);end;
end;
137
-
Exerccio 2 Soluo (cont.)
set serveroutput on;declare extenso varchar(80);begin
if(pkg_date.fn_set_idioma('english')) thenpkg_date.prc_get_date(sysdate,extenso);dbms_output.put_line(extenso || ' (' || pkg_date.fn_get_idioma || ')');
elsedbms_output.put_line('Erro ao alterar idioma');
end if;end;
138
-
Trigger
Trigger (gatilho) um programa PL/SQL que disparado automaticamente a partir da execuo de seu evento associado.
Os triggers so usados para automatizar tarefas.
Quando existe uma sequencia de comandos a ser executado, o primeiro evento pode disparar um trigger que realiza as demais tarefas.
139
-
Trigger (cont.)
Como principais motivos para o uso de database trigger, podemos citar: gerao automtica de valores derivados
de colunas preveno de transaes invlidas reforar regras de negcio complexas prover auditoria gerar estatsticas sobre acesso s tabelas prover log de transaes
140
-
Trigger (cont.)
Sintaxe: CREATE [OR REPLACE] TRIGGER BEFORE | AFTER ON [FOR EACH ROW]BEGIN
;END;
BEFORE | AFTER - indicao o momento em que o trigger ser disparado. BEFORE indica que o corpo do trigger ser executado antes
do comando que a disparou. AFTER indica que o corpo do trigger ser executado aps o
comando que a disparou.
141
-
Um trigger composto por 4 partes:1. MOMENTO
BEFORE (tabela) AFTER (tabela) INSTEAD OF (view)
2. EVENTO INSERT UPDATE DELETE
3. NVEL Instruo (STATEMENT) Linha (ROW)
4. CORPO Bloco de instrues PL/SQL
142
-
Nvel de Trigger
Triggers podem ser disparadas: No nvel de linha (Row level trigger) ou No nvel de instruo (Statement level trigger).
O cdigo de uma trigger em nvel de linha (FOR EACH ROW) executado uma vez para cada linha da tabela em que est sendo realizada uma instruo SQL. Se voc executar uma instruo UPDATE que altera 10
linhas, o cdigo do trigger ser executado 10 vezes.
J na trigger em nvel de instruo, o seu cdigo executado apenas uma vez para qualquer instruo SQL Este tipo de trigger ser executado apenas 1 vez, mesmo
para uma instruo UPDATE que altera as 10 linhas.
143
-
Registros Especiais :NEW e :OLD
Os registros especiais :NEW e :OLD armazenam temporariamente os valores do ltimo registro manipulado pelo SGBD.
Ao inserir, criado o registro :NEW Ao apagar, criado o registro :OLD Ao atualizar, so criados os 2 registros :NEW e :OLD
144
DML :OLD :NEWINSERT NULO Valores novosDELETE Valores antigos NULOUPDATE Valores antigos Valores Novos
-
Exemplo 1: Trigger para garantir que a descrio de produto seja gravada em letras maisculas.
CREATE OR REPLACE TRIGGER trg_produto_descricaoBEFORE INSERT ON tb_produtoFOR EACH ROWBEGIN
:NEW.descricao := UPPER(:NEW.descricao);END;
145
Para testar, preciso inserir um novo registro:INSERT INTO tb_produto(cod_prod, descricao, preco)
VALUES(100, 'caneta', 2.50);COMMIT;
Para exibir os erros de compilao: SHOW ERRORS;
-
Exemplo 2: Trigger para gerao automtica do cdigo.
CREATE SEQUENCE seq_produto START WITH 101;CREATE OR REPLACE TRIGGER trg_produto_codigoBEFORE INSERT ON tb_produtoFOR EACH ROWBEGIN
SELECT seq_produto.NEXTVAL INTO :NEW.cod_prodFROM DUAL;
END;
146
Para testar, vamos inserir um novo registro sem cdigo:INSERT INTO tb_produto(descricao, preco)
VALUES('lpis', 1.25);COMMIT;
-
Exemplo 3: Trigger para, caso o preo do produto seja negativo, converter para positivo.
CREATE OR REPLACE TRIGGER trg_produto_precoBEFORE INSERT ON tb_produtoFOR EACH ROWBEGIN
IF :NEW.preco < 0 THEN:NEW.preco := :NEW.preco * (-1);
END IF;
END;
147
Para testar, vamos inserir um novo registro sem cdigo:INSERT INTO tb_produto(descricao, preco)
VALUES('borracha', -2.99);COMMIT;
-
Exemplo 4: Caso o campo estoque esteja vazio, gravar o valor ZERO utilizando uma trigger.
CREATE OR REPLACE TRIGGER trg_produto_estoqueBEFORE INSERT ON tb_produtoFOR EACH ROWBEGIN
IF :NEW.estoque IS NULL THEN:NEW.estoque := 0;
END IF;
END;
148
Para testar, vamos inserir um novo registro sem cdigo:INSERT INTO tb_produto(descricao, preco)
VALUES('mouse', 45.00);COMMIT;
ALTER TABLE tb_produto ADD estoque integer;
-
Exemplo 5: Trigger para remover espaos em branco na descrio ao inserir ou atualizar.
CREATE OR REPLACE TRIGGER trg_produto_descricaoBEFORE INSERT OR UPDATE OF descricao ON tb_produto
FOR EACH ROWBEGIN
:NEW.descricao := TRIM(:NEW.descricao);END;
149
UPDATE tb_produtoSET descricao = ' MOUSE ', preco = 44.99WHERE descricao = 'MOUSE';COMMIT;
Ao indicar UPDATE OF descricao, o gatilho s ser disparado se a descrio for atualizada. Desta forma, se apenas o preo for modificado, essa trigger no ser executada.
-
Exemplo 6: Controle de histrico de preos. Ao inserir um novo produto ou atualizar seu preo, deve-se lanar em histrico.
Antes, vamos criar a tabela de histrico:
CREATE TABLE tb_produto_historico (cod_prod_hist integer not null primary key,cod_prod integer not null,preco decimal(8,2),data date,FOREIGN KEY(cod_prod) REFERENCES tb_produto(cod_prod)
);CREATE SEQUENCE seq_produto_historico START WITH 1;
150
-
Exemplo 6: Controle de histrico de preos. Ao inserir um novo produto ou atualizar seu preo, deve-se lanar em histrico.
CREATE OR REPLACE TRIGGER trg_produto_historicoAFTER INSERT OR UPDATE OF preco ON tb_produtoFOR EACH ROWBEGIN
INSERT INTO tb_produto_historico(cod_prod_hist,cod_prod, preco,data)
VALUES(seq_produto_historico.NEXTVAL,:NEW.cod_prod, :NEW.preco, SYSDATE);
END;
151
Ateno: A execuo de triggers no so retroativas. Ou seja, produtos inseridos anteriormente no sero lanados no histrico.
-
Exerccio 6 Para testar, vamos inserir e atualizar alguns produtos. Depois basta verificar se a tabela de histrico foi populada.
INSERT INTO tb_produto(descricao,preco,estoque)VALUES('Teclado', 50.00, 25);
UPDATE tb_produtoSET preco = 55.00WHERE descricao = 'TECLADO';
UPDATE tb_produtoSET preco = 60.00WHERE descricao = 'TECLADO';
UPDATE tb_produtoSET preco = 49.99WHERE descricao = 'MOUSE';
COMMIT;
152
-
Exemplo 7: Iremos registrar, tambm, o usurio responsvel pela alterao de preo.
ALTER TABLE tb_produto_historicoADD usuario varchar(100);
CREATE OR REPLACE TRIGGER trg_produto_historicoAFTER INSERT OR UPDATE OF preco ON tb_produtoFOR EACH ROWBEGIN
INSERT INTO tb_produto_historico(cod_prod_hist,cod_prod,preco,data,usuario)
VALUES(seq_produto_historico.NEXTVAL,:NEW.cod_prod, :NEW.preco, SYSDATE, USER);
END;
153
-
Exemplo 8: Impedir que a tabela de produtos seja manipulada (INSERT, UPDATE e DELETE) fora do horrio comercial.
CREATE OR REPLACE TRIGGER trg_horario_comercialBEFORE INSERT OR UPDATE OR DELETE ON tb_produtoFOR EACH ROWBEGIN
IF(TO_CHAR(SYSDATE,'HH24:MM') < '08:00'OR TO_CHAR(SYSDATE,'HH24:MM') > '18:00'OR TO_CHAR(SYSDATE,'DY') IN ('SAB', 'DOM')) THENRAISE_APPLICATION_ERROR(-20500,
'Operao no permitida nesse horrio');END IF;
END;
154
-
Habilitando e Desabilitando um trigger
Algumas vezes, quando se precisa dar manuteno na base de dados, precisando desligar temporariamente alguns triggers, para isso, usamos: ALTER TRIGGER DISABLE;
ou ALTER TABLE DISABLE ALL TRIGGERS;
Para novamente habilitar o trigger, usamos: ALTER TRIGGER ENABLE;
Caso se queira excluir definitivamente um trigger: DROP TRIGGER ;
155
-
Exerccios1. Elaborar um trigger para gerar automaticamente o cdigo do
funcionrio.2. Elaborar um trigger para formatar nome e cargo do funcionrio em
maisculas.3. Elaborar um trigger para no aceitar que o salrio seja reduzido.4. Elaborar um trigger para no permitir que o cdigo seja alterado.5. Elaborar um trigger para no permitir que um funcionrio seja excludo.6. Criar um trigger para registrar todo o histrico de cargos dos
funcionrios, registrando o cargo e a data da mudana.7. Alterar a tabela e a trigger que mantm o histrico para que seja
registrado o usurio que realizou a alterao de cargo.8. Criar uma tabela e um trigger para controlar o histrico de salrios dos
funcionrios.9. Criar um trigger para no permitir que o cargo de um funcionrio seja
alterado 2 vezes no mesmo dia.10. Criar um trigger para no permitir que o salrio de um funcionrio seja
atualizado em menos de 3 meses.156
-
Tabelas de Funcionrios e HistricosCREATE TABLE tb_funcionario(
cod_func integer not null primary key,nome varchar(80),cargo varchar(40),salario decimal(8,2),situacao char(1) default 'A', check(situacao IN('A','I')) -- Ativo ou Inativo
);CREATE TABLE tb_historico_cargo(
cod_func integer not null,cargo varchar(40),data date
);CREATE TABLE tb_historico_salario(
cod_func integer not null,salario decimal(8,2),data date
);157
Para simplificar:- cargo foi criado como um atributo.- omitiu-se as PKs e FKs no histrico.
-
Exerccio 1 Elaborar um trigger para gerar automaticamente o cdigo do funcionrio.
CREATE SEQUENCE sq_funcionarioSTART WITH 1 INCREMENT BY 1;
CREATE OR REPLACE TRIGGER tg_funcionario_codigoBEFORE INSERT ON tb_funcionarioFOR EACH ROWBEGIN
SELECT sq_funcionario.NEXTVALINTO :NEW.cod_funcFROM dual;
END;
158
-
Exerccio 2 Elaborar um trigger para formatar nome e cargo do funcionrio em maisculas.
CREATE OR REPLACE TRIGGER tg_funcionario_maiusculasBEFORE INSERT OR UPDATE ON tb_funcionarioFOR EACH ROWBEGIN
:NEW.nome := UPPER(:NEW.nome);:NEW.cargo := UPPER(:NEW.cargo);
END;
159
-
Exerccio 3 Elaborar um trigger para no aceitar que o salrio seja reduzido.
CREATE OR REPLACE TRIGGER tg_funcionario_salarioBEFORE UPDATE OF salario ON tb_funcionarioFOR EACH ROWBEGIN
IF :NEW.salario < :OLD.salario THENRAISE_APPLICATION_ERROR(-20500,
'No permitido reduzir o salrio');END IF;
END;
160
-
Exerccio 4 Elaborar um trigger para no permitir que o cdigo seja alterado.
CREATE OR REPLACE TRIGGER tg_funcionario_alterar_codigoBEFORE UPDATE OF cod_func ON tb_funcionarioFOR EACH ROWBEGIN
RAISE_APPLICATION_ERROR(-20501,'No permitido alterar o cdigo');
END;
161
-
Exerccio 5 Elaborar um trigger para no permitir que um funcionrio seja excludo.
CREATE OR REPLACE TRIGGER tg_funcionario_alterar_codigoBEFORE DELETE ON tb_funcionarioFOR EACH ROWBEGIN
RAISE_APPLICATION_ERROR(-20501,'No permitido excluir fisicamente um registro');
END;
162
-
Exerccio 6 Criar um trigger para registrar todo o histrico de cargos dos funcionrios, registrando o cargo e a data da mudana.
CREATE OR REPLACE TRIGGER tg_historico_cargoAFTER INSERT OR UPDATE OF cargo ON tb_funcionarioFOR EACH ROWBEGIN
INSERT INTO tb_historico_cargo(cod_func, cargo, data)VALUES(:NEW.cod_func, :NEW.cargo, SYSDATE);
END;
163
-
Exerccio 7 Alterar a tabela e a trigger que mantm o histrico para que seja registrado o usurio que realizou a alterao de cargo.
ALTER TABLE tb_historico_cargo ADD usuario varchar(80);
CREATE OR REPLACE TRIGGER tg_historico_cargoAFTER INSERT OR UPDATE OF cargo ON tb_funcionarioFOR EACH ROWBEGIN
INSERT INTO tb_historico_cargo(cod_func, cargo, data, usuario)
VALUES(:NEW.cod_func, :NEW.cargo, SYSDATE, USER);END;
164
-
Exerccio 8 Criar uma tabela e um triggerpara controlar o histrico de salrios dos funcionrios.
CREATE OR REPLACE TRIGGER tg_historico_salarioAFTER INSERT OR UPDATE OF salario ON tb_funcionarioFOR EACH ROWBEGIN
INSERT INTO tb_historico_salario(cod_func, salario, data)VALUES(:NEW.cod_func, :NEW.salario, SYSDATE);
END;
165
-
Exerccio 9 Criar um trigger para no permitir que o cargo de um funcionrio seja alterado 2 vezes no mesmo dia.
create or replace trigger tg_validar_cargobefore update of cargo on tb_funcionariofor each rowdeclare
v_qtde number;begin
select count(*) into v_qtdefrom tb_historico_cargowhere cod_func = :new.cod_func
and trunc(data) = trunc(sysdate);if v_qtde 0 then
raise_application_error(-20503,'No permitido trocar de cargo no mesmo dia');
end if;end;
166
-
Exerccio 10 Criar um trigger para no permitir que o salrio de um funcionrio seja atualizado em menos de 3 meses.
create or replace trigger tg_validar_cargobefore update of salario on tb_funcionariofor each rowdeclare
v_qtde number;begin
select count(*) into v_qtdefrom tb_historico_cargowhere cod_func = :new.cod_func
and trunc(data) >= trunc(add_months(sysdate,-3));if v_qtde 0 then
raise_application_error(-20503,'Salrio j alterado a menos de 3 meses');
end if;end;
167
-
Exerccios
1. Criar uma tabela chamada tb_produto_estatistica com os campos: qtde_produtos e preco_medio. Cada vez que a tabela de produtos for manipulada (insert, update ou delete), deve-se disparar um trigger para atualizar os dados da tabela de estatsticas.
2. Criar uma tabela chamada tb_produto_auditoria com os campos: usuario, data, evento (Insert, Update, Delete), codigo_antigo, codigo_novo, descricao_antiga, descricao_nova, preco_antigo e preco_novo. Cada vez que a tabela de produtos for manipulada, deve-se disparar um trigger para criar a trilha para auditoria.
168
-
Controle de Estoque por Trigger1. Criar um trigger para dar baixa no estoque cada vez que
um novo item for adicionado no pedido.2. Criar um trigger para restaurar o estoque caso um item
seja removido do pedido.3. Criar um trigger para ajustar o estoque caso a
quantidade seja alterada.4. Remover os 3 triggers criados para controlar o estoque
de produtos.5. Criar um nico trigger que ir fazer todo o controle do
estoque (insert, update e delete).6. Criar um nico trigger que ir fazer a atualizao do
campo valor na tabela de pedido, sempre que a tabela de itens for manipulada.
169
-
Tabelas de PedidosCREATE TABLE tb_pedido(
cod_ped integer not null primary key,data date,valor decimal(8,2) default 0
);
CREATE TABLE tb_itens(cod_ped integer not null,cod_prod integer not null,qtde integer,PRIMARY KEY(cod_ped, cod_prod),FOREIGN KEY(cod_ped) REFERENCES tb_pedido(cod_ped),FOREIGN KEY(cod_prod) REFERENCES tb_pedido(cod_prod)
);
UPDATE tb_produto SET estoque = 100;
170
-
Exerccio 1 Criar um trigger para dar baixa no estoque cada vez que um novo item for adicionado no pedido.
CREATE OR REPLACE tg_estoque_baixarAFTER INSERT ON tb_itensFOR EACH ROWBEGIN
UPDATE tb_produtoSET estoque = estoque - :NEW.qtdeWHERE cod_prod = :NEW.cod_prod;
END;
171
-
Exerccio 2 Criar um trigger para restaurar o estoque caso um item seja removido do pedido.
CREATE OR REPLACE tg_estoque_restaurarAFTER DELETE ON tb_itensFOR EACH ROWBEGIN
UPDATE tb_produtoSET estoque = estoque + :OLD.qtdeWHERE cod_prod = :OLD.cod_prod;
END;
172
-
Exerccio 3 Criar um trigger para ajustar o estoque caso a quantidade seja alterada.
CREATE OR REPLACE tg_estoque_ajustarAFTER UPDATE ON tb_itensFOR EACH ROWBEGIN
UPDATE tb_produtoSET estoque = estoque + :OLD.qtde - :NEW.qtdeWHERE cod_prod = :NEW.cod_prod;
END;
173
-
Exerccio 4 Remover os 3 triggers criados para controlar o estoque de produtos.
DROP TRIGGER tg_estoque_baixar;DROP TRIGGER tg_estoque_restaurar;DROP TRIGGER tg_estoque_ajustar;
174
-
Exerccio 5 Criar uma nica trigger que ir fazer todo o controle do estoque.
CREATE OR REPLACE TRIGGER tg_estoqueAFTER INSERT OR UPDATE OR DELETE ON tb_itensFOR EACH ROWBEGIN
IF INSERTING THENUPDATE tb_produtoSET estoque = estoque - :NEW.qtdeWHERE cod_prod = :NEW.cod_prod;
ELSIF DELETING THENUPDATE tb_produtoSET estoque = estoque + :OLD.qtdeWHERE cod_prod = :OLD.cod_prod;
ELSIF UPDATING THENUPDATE tb_produtoSET estoque = estoque + :OLD.qtde - :NEW.qtdeWHERE cod_prod = :NEW.cod_prod;
END IF;END;
175
predicados condicionais
-
Trigger para Eventos do Sistema
Num trigger, podemos fazer referencia a um evento do sistema ao invs de referenciarmos uma tabela.
Os eventos de sistema so: AFTER SERVERERROR AFTER LOGON BEFORE LOGOFF AFTER STARTUP BEFORE SHUTDOWN
Voc pode criar triggers usando os eventos acima para DATABASE e SCHEMA. As duas excees so SHUTDOWN e STARTUP que s se
aplicam a DATABASE
176
-
Log para Controle de Acessos
Vamos criar a tabela de log de acesso e seu sinnimo:
CREATE TABLE tb_log_acesso (usuario varchar(80),horario char(20),evento char(6)
);
CREATE PUBLIC SYNONYM log_acesso_IDFOR SYSTEM.tb_log_acesso;
177
-
Trigger para registrar o logon
CREATE OR REPLACE TRIGGER tg_registrar_logonAFTER LOGON ON DATABASEBEGIN
INSERT INTO log_acesso_ID VALUES(USER, TO_CHAR(sysdate, 'DD-MM-YYYY HH24:MI:SS'),'LOGON');
COMMIT; END;
178
-
Trigger para registrar o logoff
CREATE OR REPLACE TRIGGER tg_registrar_logoffBEFORE LOGOFF ON DATABASEBEGIN
INSERT INTO log_acesso_ID VALUES(USER, TO_CHAR(sysdate, 'DD-MM-YYYY HH24:MI:SS'),'LOGOFF');
COMMIT; END;
179
-
Trigger com Tabela Mutante
Uma tabela mutante (MUTATING TABLE) uma tabela que est sendo modificada atualmente por uma instruo UPDATE, DELETE ou INSERT.
Quando criamos um trigger para determinada tabela e, dentro dela, tentamos manipular os dados dessa mesma tabela, enfrentamos o problema de trigger mutante.
O cdigo de erro Oracle ORA-04091 Isso ocorre porque o trigger executado no momento de
manipulao da tabela e o objeto (tabela) est em modo bloqueado at que se encerre.
Uma tabela s considerada mutante para gatilhos de linha (FOR EACH ROW).
180
-
Exemplo de Trigger Mutante
create or replace trigger tg_verificar_reserva_quartobefore insert or update on tb_reservasfor each rowdeclare cursor cur_reservas is
select * from tb_reservaswhere num_quarto = :new.num_quarto and(dt_entrada between :new.dt_entrada and :new.dt_saidaor dt_saida between :new.dt_entrada and :new.dt_saida);
beginfor reg_reservas in cur_reservas loop
raise_application_error(-20001,'Quarto j possui reserva para este perodo');
end loop;end;
181
-
Possveis Solues:
No use trigger Uma maneira de evitar o erro de tabela mutante no usar
trigger.
Use after or "instead of Se voc usar um gatilho AFTER para um trigger que ir atualizar
uma tabela, a atualizao j estar concluda quando o trigger for executado e a tabela no ser mutante.
Reescreva a sintaxe da trigger Existem algumas maneiras de evitar o erro de tabela mutante
com uma combinao de gatilhos de nvel de linha e de instruo.
Use autonomous transactions Voc pode evitar o erro de tabela mutante, marcando seu gatilho
como uma transao autnoma, tornando-se independente da tabela que chama o procedimento.
182
-
Resumo
PL/SQL Linguagem que rene recursos da linguagem SQL com instrues de controle tpicas de linguagens de programao procedurais.
BLOCOS ANONIMOS instrues PL/SQL que permitem a realizao de rotinas junto ao banco de dados e que no ficam registrados no servidor.
STORED PROCEDURES programas PL/SQL que permitem uso de passagem de parmetros e que, aps compilados, ficam gravados no servidor e podem ser executados atravs de linguagens de programao.
FUNCTION programas PL/SQL que podem receber parmetros e que sempre retornam um resultado.
TRIGGER programas PL/SQL que so disparados automaticamente pelo BD quando um evento associados executado.
183
-
Elaborar um trigger para gerar automaticamente as parcelas das contas a receber a venda. A venda deve possuir: num_venda, data_venda, valor_venda, qtde_parcelas. Em contas a receber deve-se armazenar: num_venda, num_parcela, data_vecto, valor e situao ((P) pendente ou (Q) quitado). A partir do numero de parcelas da venda, deve-se criar as parcelas em contas a receber. A data da primeira parcela deve ser igual a data de venda. As demais parcelas devem ter o mesmo dia nos meses seguintes. A soma de todas as parcelas deve ser exatamente o valor total da venda. A situao inicial de todas as parcelas dever ser pendente.
184
Trabalho(individual ou em dupla)
-
BibliografiaLivro Texto:1. Introduo a Sistemas de Banco de Dados; Date, C. J.; Ed. Campus; 8 edio; 2004;
15 exemplares.2. Sistemas de Banco de Dados; Korth, Henry F.; Ed. Campus; 5 edio; 2006; 15
exemplares.3. Oracle Database 11g PL/SQL: Programao; McLaughlin, Michel; Ed. Novatec; 1
edio; 2009; 10 exemplares.
Complementar:4. Projeto e Modelagem de Banco de Dados; Lightstone, Teorey; Ed. Campus; 1 edio;
2006; 10 exemplares.5. Oracle 10g PL/SQL; Oliveira, Celso H. Poderoso de; Ed. Novatec; 1 edio; 2005; 10
exemplares.6. Oracle 10g Database: Guia do DBA; Serson, Roberto Rubinstein; Ed. Novatec; 1 edio;
2004; 10 exemplares.7. Oracle 10g: Ideal Para Quem Deseja Iniciar o Aprendizado do Oracle; Ramalho, Jos
A.; Ed. Thomson; 1 edio; 2005; 10 exemplares.8. Gerenciando Banco de Dados: A Abordagem Entidade-Relacionamento para Projeto
Lgico; Chen, Peter; Makron Books; 1 edio; 1990; 7 exemplares.
185