Sei sulla pagina 1di 43

Equipe de monitoria

Aula prática 3
 Caso de estudo
 Igualando situações
 Cursor
 Function
 Procedure
 Trigger
 Package
 Surpresa...
 Mesmo da aula passada, para quem não terminou
de gerar o banco...
 Pegar arquivo BD.zip em www.cin.ufpe.br/~rcm3/GDI
 Descompactar arquivo:
▪ criacaoTabelas.SQL
▪ popularBD.SQL
▪ logico
▪ LOGICO.brM
▪ Modelo Logico - Aula Prática.jpg
▪ conceitual
▪ CONCEITUAL.brM
▪ Modelo Conceitual - Aula Pratica.jpg
 Criar as tabelas
 Executar script em criacaoTabelas.SQL
 Popular base de dados
 Executar script em popularBD.SQL

Observação: apenas uma pessoa por equipe realize


essas tarefas para evitar exceções.
 SELECT * FROM tabs;
 DESCRIBE nometabela ou DESC nometabela;
 SELECT * FROM user_triggers;
 SELECT * FROM user_procedures;
 SELECT * FROM user_sequences;
 SHOW errors;
 SET serveroutput on
Definições
 Quando uma query é executada no Oracle, um
result set é produzido e salvo em memória. Oracle
permite ao programador acessar este result set em
memória através de Cursores.

 Muitas vezes, quando uma query retorna mais de


uma linha como resultado, seria interessante iterar
sobre cada linha e processar os dados de uma
maneira diferente para elas. Cursores são úteis
neste caso.
 Declarar (Declare)
 Dá um nome ao cursor e o associa a uma query
que retornará múltiplas linhas
 Abrir (Open)
 Executa a query
 Acessar (Fetch)
 Fechar (Close)
 Encerra o processamento do cursor
 Durante os exemplos e exercícios da aula,
será possível ver utilizações práticas de
cursores.
Exemplos (contextualizado ou não) e exercício
 Utilizado para modularizar uma consulta, a
qual pode ser utilizada em diversos locais,
sem necessidade de repetição de código.
 Sempre possui retorno.

CREATE [OR REPLACE ]FUNCTION <nome>


[(parâmetro [{IN | OUT | IN OUT}] tipo, ....)]
RETURN <tipo-retorno> {IS | AS}
BEGIN <corpo-do-procedimento>
END <nome>;
 Sem contextualização
 Informadas duas datas, montar uma String
de retorno contendo o período entre essas
duas datas.
CREATE OR REPLACE FUNCTION retornarPeriodo (dtInicial
DATE, dtFinal DATE)
RETURN VARCHAR2 IS
retorno VARCHAR2(60);
BEGIN
SELECT CONCAT (dtInicial, ' a ') INTO retorno FROM DUAL;
SELECT CONCAT (retorno, dtfinal) INTO retorno FROM DUAL;
return retorno;
END;
SELECT
retornarperiodo(to_date('2008/03/15', 'yyyy/MM/dd'),
to_date('2008/11/25', 'yyyy/MM/dd'))
from dual;
 Criar uma função que, passada um cargo
como argumento, retorne a média salarial
dos funcionários com aquele cargo.
CREATE OR REPLACE FUNCTION
media_por_cargo (crg Funcionario.Cargo%TYPE)
RETURN NUMBER
IS
v_media NUMBER;
BEGIN
SELECT AVG (salario) INTO v_media FROM
funcionario F WHERE F.Cargo LIKE crg;
RETURN v_media;
END media_por_cargo;
 Faça uma função que recebe o nome do
esporte e retorna a quantidade de atletas que
praticam esse esporte.
create or replace
FUNCTION atletas_por_esporte(esporte Esporte.Nome%TYPE) RETURN
NUMBER IS qnt_atletas NUMBER;

BEGIN

SELECT COUNT(E.Nome) INTO qnt_atletas FROM Esporte E, Modalidade


M, Equipe E, Compoe C
WHERE E.Nome LIKE esporte AND M.codigoesp = E.CodigoEsp AND
E.numseq = M.numseq AND E.codigoEquipe = C.codigoEquipe;
RETURN qnt_atletas;

END atletas_por_esporte;
Exemplos e exercício
 Utilizado para modularizar uma ação, a qual
pode ser reutilizada diversas vezes, sem
necessidade de repetição de código.
 Não possui retorno. Todas as ações
necessárias são realizadas dentro do corpo do
procedimento
CREATE [OR REPLACE] PROCEDURE <nome>
[(parâmetro [{IN | OUT | IN OUT}] tipo, ....)]
{IS | AS}
<definições de variáveis>
BEGIN <corpo-do-procedimento>
END <nome>;
 Crie uma Procedure que, dada uma equipe,
imprima todos os títulos que ela possui.
CREATE OR REPLACE PROCEDURE equipeTitulos (codigoEq
EQUIPE.CODIGOEQUIPE%TYPE) IS
CURSOR cur_titulos IS SELECT CodigoTit FROM
DisputaEquiCamp WHERE CodigoEquipe = codigoEq;
titulo DISPUTAEQUICAMP.CODIGOTIT%TYPE;
BEGIN
OPEN cur_titulos;
LOOP
FETCH cur_titulos INTO titulo;
EXIT WHEN cur_titulos%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Titulo de código: ' || to_char(titulo));
END LOOP;
CLOSE cur_titulos;
END;
 Criar uma procedure que atualiza o salário de
determinado funcionário. Caso o funcionário
não exista, emita uma mensagem de alerta;
CREATE OR REPLACE PROCEDURE setSalario (codigoFunc
FUNCIONARIO.CODIGO%TYPE, sal_novo
FUNCIONARIO.SALARIO%TYPE) AS
nome_func PESSOA.NOME%TYPE;
CURSOR cursor_func IS SELECT P.Nome FROM Pessoa P, Funcionario F
WHERE F.Codigo = codigoFunc AND F.Codigo = P.Codigo;
BEGIN
OPEN cursor_func;
FETCH cursor_func INTO nome_func;
IF cursor_func%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('O Funcionário de código ' ||
to_char(codigoFunc) || ' não existe');
ELSE
UPDATE Funcionario SET Salario = sal_novo WHERE Codigo =
codigoFunc;
DBMS_OUTPUT.PUT_LINE('Funcionario ' || to_char(nome_func) || '
teve seu salário alterado para ' || sal_novo);
END IF;
CLOSE cursor_func;
END setSalario;
Exercício
 Utilizado para executar uma ação quando
uma outra acontecer, ou seja:
 Quando uma determinada ação acontece, uma
reação é acionada.

 Cuidado com:
 Tabelas mutantes
 Especificação das restrições de acontecimento
CREATE [ OR REPLACE ] TRIGGER <nome>
[ BEFORE | AFTER | INSTEAD OF ] <evento>
ON <tabela>
[REFERENCING NEW AS <novo_nome>
OLD AS <antigo_nome> ]
[ FOR EACH ROW [ WHEN <condição> ] ]
[ DECLARE PRAGMA
AUTONOMOUS_TRANSACTION ]
BEGIN <corpo-do-procedimento>
END <nome>;
 Uso de BEFORE possibilita o acesso a valores
antigos e novos
 Uso de FOR EACH ROW gera várias
execuções do gatilho
 A opção FOR EACH ROW determina se o
gatilho é do tipo row trigger ou statement
trigger
 Se especificada, o gatilho é executado UMA vez
para cada tupla afetada pelo evento
 Se omitida, o gatilho é executado UMA ÚNICA vez
para cada ocorrência de evento
 A opção WHEN:
 É usada apenas com row triggers
 Consiste em uma expressão booleana – SQL
 Não pode incluir:
▪ Subconsultas
▪ Expressões em PL/SQL
▪ Funções definidas pelo usuário
 Criar uma tabela de auditoria para as
alterações feitas na tabela funcionário que
guarde o usuário, o tipo e a data da
modificação feita na tabela bem como os
dados modificados do CREATE TABLE auditorlog (
audit_date DATE,
funcionário audit_user VARCHAR2(30),
audit_desc VARCHAR2(30),
(código, cargo, salário). old_func_id NUMBER(7),
old_func_carg VARCHAR2(40),
old_func_sal NUMBER(7,2),
new_func_id NUMBER(7),
new_func_carg VARCHAR2(40),
new_func_sal NUMBER(7,2)
);
CREATE OR REPLACE TRIGGER auditor_trig
AFTER INSERT OR UPDATE OR DELETE ON funcionario
FOR EACH ROW
DECLARE
v_alteracao CHAR(30);
BEGIN
IF INSERTING THEN
v_alteracao := 'Funcionario Adicionado';
ELSIF UPDATING THEN
v_alteracao := 'Funcionario Alterado';
ELSE
v_alteracao := 'Funcionario Deletado';
END IF;
INSERT INTO auditorlog
(audit_desc, audit_user, audit_date,
old_func_id, old_func_carg, old_func_sal,
new_func_id, new_func_carg, new_func_sal)
VALUES
(v_alteracao, USER, SYSDATE,
:old.codigo, :old.cargo, :old.salario,
:new.codigo, :new.cargo, :new.salario);
END auditor_trig;
/
Exemplo e exercício
 Utilizado para melhor organização dos
elementos do banco de dados.
 Na definição do pacote só é apresentada a
especificação do mesmo
 A implementação é apresentada à parte através
do corpo do pacote
CREATE [OR REPLACE] PACKAGE <nome> {IS|AS}
<especificação de procedimento> |
< especificação de procedimento função>|
<declaração de variável> |
<definição de tipo> |
<declaração de exceção> |
<declaração de cursor>
END <nome>;

CREATE [OR REPLACE] PACKAGE BODY <nome> {IS|AS}


<implementações do que foi especificado>
END <nome>;
 Crie um Package onde, dada uma equipe sejam
listadas as modalidades relacionadas a ela.
CREATE OR REPLACE PACKAGE manipula_modalidade IS

FUNCTION contar_modalidade (codigo_esporte IN


esporte.codigoesp%TYPE) RETURN BINARY_INTEGER;

PROCEDURE listar_modalidade (codigo_esporte IN


esporte.codigoesp%TYPE);

END manipula_modalidade;
/
 Continuação
CREATE OR REPLACE PACKAGE BODY manipula_modalidade AS

FUNCTION contar_modalidade (codigo_esporte IN esporte.codigoesp%TYPE)


RETURN BINARY_INTEGER IS quantidade BINARY_INTEGER;

BEGIN
SELECT COUNT(*) INTO quantidade FROM modalidade m where
m.codigoesp = codigo_esporte;
RETURN quantidade;
END contar_modalidade;

PROCEDURE listar_modalidade (codigo_esporte IN esporte.codigoesp%TYPE) IS

quantidade NUMBER(3);
CURSOR selecao_modalidades IS (SELECT m.descricao, m.codigoesp
FROM modalidade m where m.codigoesp = codigo_esporte);
registro selecao_modalidades%rowType;
 Continuação
BEGIN
SELECT contar_modalidade (codigo_esporte) INTO quantidade from
dual;
OPEN selecao_modalidades;
WHILE quantidade > 0 LOOP
FETCH selecao_modalidades INTO registro.descricao,
registro.codigoesp;
dbms_output.put_line (registro.descricao);
quantidade := quantidade - 1;
END LOOP;
CLOSE selecao_modalidades;
END listar_modalidade;

END manipula_modalidade;
/
 Crie um Package que insere uma nova equipe
e logo em seguida imprime a tabela de
equipes atualizada;
CREATE OR REPLACE PACKAGE manipula_esporte IS

PROCEDURE inserir_esporte ( novo_nome IN esporte.nome%TYPE,


novo_codigo IN esporte.codigoesp%TYPE);

PROCEDURE listar_esporte;

END manipula_esporte;
/
 Continuação
CREATE OR REPLACE PACKAGE BODY manipula_esporte AS

PROCEDURE inserir_esporte ( novo_nome IN esporte.nome%TYPE, novo_codigo


IN esporte.codigoesp%TYPE) IS

BEGIN
INSERT INTO esporte (nome, codigoesp) VALUES (novo_nome,
novo_codigo);
COMMIT;
listar_esporte;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
RAISE_APPLICATION_ERROR(-20011, ‘Esporte já cadastrado');

END inserir_esporte;
 Continuação
PROCEDURE listar_esporte IS
quantidade number(3);
CURSOR selecao_esportes is SELECT * from esporte;
registro selecao_esportes%rowType;
BEGIN
OPEN selecao_esportes;
SELECT COUNT(*) into quantidade from esporte;
WHILE quantidade > 0 LOOP
FETCH selecao_esportes INTO registro.nome, registro.codigoesp;
dbms_output.put_line (registro.nome || ' ' ||
TO_CHAR(registro.codigoesp));
quantidade := quantidade - 1;
END LOOP;
CLOSE selecao_esportes;
END listar_esporte;
END manipula_esporte;
/
 Mesmas regras
 Consultas a serem respondidas apenas pelos
alunos. Valendo NOTA!
 As respostas devem ser enviadas a
rcm3@cin.ufpe.br até hoje.
 Só vale para os alunos aqui presentes, ou seja,
para quem ficou até o final da aula! =D
 Os email devem seguir o padrão estabelecido,
caso contrário, não serão aceitos.
1. Devemos garantir que todo funcionário, que
não seja 'Gerente', ao ser contratado não irá
receber um salário menor que o menor
existente para o seu determinado cargo,
como também, não irá receber um salário
maior que o maior existente para o seu
determinado cargo.
2. Queremos dar um aumento de 10% para
todos os funcionários que são
coordenadores de Atletismo. Resolva
usando uma procedure e um cursor local,
todos dentro do mesmo package.
Muito obrigado!

Potrebbero piacerti anche