Escolar Documentos
Profissional Documentos
Cultura Documentos
de Dados
Apresentação
A manipulação de banco de dados às vezes necessita, além dos comandos básicos, da criação de
estruturas de códigos mais complexas e robustas. Exemplos dessas estruturas são os elementos
Procedure, Function e Triggers, que permitem a criação de blocos de códigos, com procedimentos,
parâmetros de entrada/saída, possibilitam trabalhar com os tipos de dados e disparar
procedimentos no banco de dados de forma reativa. Bons administradores de banco de dados
utilizam esses elementos diariamente a fim de garantir que processos sejam realizados
automaticamente, de forma adequada e organizada. Sendo assim, é fundamental entender estas
estruturas para conseguir realizar uma boa administração de banco de dados. Nesta Unidade de
Aprendizagem, você irá entender cada uma delas, conhecer alguns exemplos e identificar quando
aplicá-las adequadamente.
Bons estudos.
No entanto, o sistema é utilizado por diversas filiais que rodam instâncias separadas do sistema e,
uma possível alteração na tabela implicaria em uma alteração no código de cada uma dessas filiais.
Como forma de facilitar a manutenção desse sistema, você poderia criar uma procedure para
executar o seguinte comando SQL.
Também é preciso limitar, com a cláusula WHERE, para retornar apenas os registros criados no dia
(com CURDATE()).
Sua missão é:
1 - Criar e descrever o comando de uma PROCEDURE que consulta todos os produtos da tabela
‘Produto’ ordenando pela data de criação em ordem decrescente.
2 - Descrever o comando para executar esta procedure.
3 - Modificar a procedure criada para pesquisar por produtos pela coluna nome.
4 - Descrever como ficaria o comando para executar a procedure do item 3, buscando pelo produto
“batom”.
Infográfico
Veja, no Infográfico a seguir, as rotinas de banco de dados que, entre outras vantagens, permitem a
automatização de processos diretamente no SGBD.
Conteúdo do livro
No trecho Procedimentos do PL/SQL, da obra Projeto, Desenvolvimento de Aplicações &
Administração de Banco de Dados, você aprenderá, a partir de exemplos, sobre os procedimentos no
PL/SQL, que são blocos nomeados com um conjunto operacional de parâmetros.
Boa leitura.
TRADUÇÃO DA
TERCEIRA EDIÇÃO
Michael V. Mannino
M284p Mannino, Michael V.
Projeto, desenvolvimento de aplicações e administração
de banco de dados [recurso eletrônico] / Michael V.
Mannino ; tradução: Beth Honorato ... [et al.] ; revisão
técnica: Antônio Fernandes Nunes Guardado, Sidney da
Silva Viana. – 3. ed. – Dados eletrônicos. – Porto Alegre:
AMGH, 2014.
CDD 005.74
CDU 004.658
Esta seção trata dos pacotes, das funções e dos procedimentos em PL/SQL. Algumas
partes adicionais do PL/SQL (cursores e exceções) são apresentadas para demonstrar a utili-
dade dos procedimentos armazenados. Os scripts de teste pressupõem o preenchimento das
tabelas da universidade, conforme os dados no site do livro.
Estrutura de Procedimento:
CREATE [OR REPLACE] PROCEDURE NomeProcedimento
[ ( Parâmetro1, . . . , ParâmetroN ) ]
IS
[ seqüência de declarações ]
BEGIN
seqüência de instruções
[ EXCEPTION
seqüência de instruções para responder às exceções ]
END;
EXEMPLO 11.13 Procedimento para Inserir uma Linha na Tabela Registro Acompanhado de
Código para Testar o Procedimento
CREATE OR REPLACE PROCEDURE pr_IncluirRegistro
(vNumReg IN Registro.NumReg%TYPE,
vCPFAluno IN Registro.CPFAluno%TYPE,
vSituacaoReg IN Registro.SituacaoReg%TYPE,
vDataReg IN Registro.DataReg%TYPE,
vTrimestreReg IN Registro.TrimestreReg%TYPE,
vAnoReg IN Registro.AnoReg%TYPE) IS
-- Cria um novo registro
BEGIN
INSERT INTO Registro
(NumReg, CPFAluno, SituacaoReg, DataReg, TrimestreReg, AnoReg)
VALUES (vNumReg, vCPFAluno, vSituacaoReg, vDataReg, vTrimestreReg,
vAnoReg);
390 Parte Cinco Desenvolvimento de Aplicação com Bancos de Dados Relacionais
EXEMPLO 11.14 Procedimento para Inserir uma Linha na Tabela Registro Acompanhada de
Código para Testar o Procedimento
CREATE OR REPLACE PROCEDURE pr_IncluirRegistro
(vNumReg IN Registro.NumReg%TYPE,
vCPFAluno IN Registro.CPFAluno%TYPE,
vSituacaoReg IN Registro.SituacaoReg%TYPE,
vDataReg IN Registro.DataReg%TYPE,
vTrimestreReg IN Registro.TrimestreReg%TYPE,
vAnoReg IN Registro.AnoReg%TYPE,
vResultado OUT BOOLEAN ) IS
-- Cria um novo registro
-- vResultado é TRUE se completado com sucesso, do contrário, é falso.
BEGIN
vResultado := TRUE;
INSERT INTO Registro
(NumReg, CPFAluno, SituacaoReg, DataReg, TrimestreReg, AnoReg)
VALUES (vNumReg, vCPFAluno, vSituacaoReg, vDataReg, vTrimestreReg,
vAnoReg);
Capítulo 11 Procedimentos Armazenados e Gatilhos 391
EXCEPTION
WHEN OTHERS THEN vResultado := FALSE;
END;
/
-- Código de teste
SET SERVEROUTPUT ON;
-- Número de linhas antes da execução do procedimento
SELECT COUNT(*) FROM Registro;
DECLARE
-- Parâmetro de saída deve ser declarado no bloco de chamada
Resultado BOOLEAN;
BEGIN
-- Esse teste deve se completado com sucesso.
-- O procedimento atribui valor ao parâmetro de saída (Resultado).
pr_IncluirRegistro
(1275,'901-23-4567','F',To_Date('27-Fev-2006'),'Primavera',2006,Resultado);
IF Resultado THEN
dbms_output.put_line('Adicionada uma linha na tabela Registro');
ELSE
dbms_output.put_line('Linha não adicionada na tabela Registro');
END IF;
-- Esse teste deve falhar por causa da chave primária em duplicidade.
pr_IncluirRegistro
(1275,'901-23-4567','F',To_Date('27-Fev-2006'), 'Primavera',2006,Resultado);
IF Resultado THEN
dbms_output.put_line('Adicionada uma linha na tabela Registro');
ELSE
dbms_output.put_line('Linha não adicionada na tabela Registro');
END IF;
END;
/
-- Número de linhas depois das execuções do procedimento
SELECT COUNT(*) FROM Registro;
-- Exclui a linha inserida
ROLLBACK;
TABELA 11.4
Exceção Quando Acionada
Lista de Exceções
Predefinidas Comuns Cursor_Already_Open Tenta abrir um cursor já aberto anteriormente
do PL/SQL Dup_Val_On_Index Tenta armazenar um valor em duplicidade em um índice único
Invalid_Cursor Tenta executar uma operação inválida em um cursor, como, por
exemplo, fechar um cursor não aberto anteriormente
No_Data_Found A instrução SELECT INTO não retorna nenhuma linha
Rowtype_Mismatch Tenta designar valores com tipos de dados incompatíveis entre um
cursor e uma variável
Timeout_On_Resource Tempo limite, por exemplo, quando se aguarda por um bloqueio exclusivo1
Too_Many_Rows A instrução SELECT INTO retorna mais de uma linha
1
No Capítulo 15, será explicado o uso de tempo-limite com bloqueio de transação para evitar deadlocks.
392 Parte Cinco Desenvolvimento de Aplicação com Bancos de Dados Relacionais
EXEMPLO 11.15 Função para Recuperar o Nome do Aluno Dado seu Número do CPF
CREATE OR REPLACE FUNCTION fn_RecuperarNomeAluno
(vCPFAluno IN Aluno.CPFAluno%type) RETURN VARCHAR2 IS
-- Recupera o nome do aluno (concatena o nome e sobrenome)
-- dado o número do CPF do aluno. Se o aluno não existe,
-- retorna nulo.
vNomeAluno Aluno.NomeAluno%TYPE;
vSobrenomeAluno Aluno.SobrenomeAluno%TYPE;
BEGIN
SELECT NomeAluno, SobrenomeAluno
INTO vNomeAluno, vSobrenomeAluno
FROM Aluno
WHERE CPFAluno = vCPFAluno;
RETURN(vSobrenomeAluno || ', ' || vNomeAluno);
Capítulo 11 Procedimentos Armazenados e Gatilhos 393
EXCEPTION
-- No_Data_Found é disparado se a instrução SELECT não retorna nenhum dado.
WHEN No_Data_Found THEN
RETURN(NULL);
WHEN OTHERS THEN
raise_application_error(-20001, 'Database error');
END;
/
-- Código de teste
SET SERVEROUTPUT ON;
DECLARE
vNomeAluno VARCHAR2(50);
BEGIN
-- Essa chamada deve mostrar o nome de um aluno.
vNomeAluno := fn_RecuperarNomeAluno('901-23-4567');
IF vNomeAluno IS NULL THEN
dbms_output.put_line('Aluno não encontrado');
ELSE
dbms_output.put_line('Nome é ' || vNomeAluno);
END IF;
-- Essa chamada não deve mostrar o nome de um aluno.
vNomeAluno := fn_RecuperarNomeAluno('905-23-4567');
IF vNomeAluno IS NULL THEN
dbms_output.put_line('Aluno não encontrado');
ELSE
dbms_output.put_line('Nome é ' || vNomeAluno);
END IF;
END;
/
O Exemplo 11.16 mostra uma função com uma consulta mais complexa que a função do
Exemplo 11.15. O código de teste contém dois casos para testar, procurando um aluno exis-
tente e um aluno não existente, juntamente com a instrução SELECT que utiliza a função no
resultado. Uma vantagem importante das funções é que elas podem ser utilizadas em ex-
pressões nas instruções SELECT.
EXEMPLO 11.16 Função para Computar a Média de Notas Ponderada Dados o Número do CPF
e o Ano do Aluno
CREATE OR REPLACE FUNCTION fn_CalcularMediaPonderada
(vCPFAluno IN Aluno.CPFAluno%TYPE, vAno IN Oferecimento.AnoOfer%TYPE)
RETURN NUMBER IS
-- Computa a média de notas ponderada dados o ano e o número do CPF do
aluno.
-- Média ponderada é a soma das cargas horárias multiplicada pela nota
-- dividida por cargas horárias totais.
-- Se o aluno não existe, retorna nulo.
MediaPonderada NUMBER;
394 Parte Cinco Desenvolvimento de Aplicação com Bancos de Dados Relacionais
BEGIN
SELECT SUM (NotaMatr*CargaHoraCurso) / SUM(CargaHoraCurso)
INTO MediaPonderada
FROM Aluno, Registro, Matricula, Oferecimento, Curso
WHERE Aluno.CPFAluno = vCPFAluno
AND Oferecimento.AnoOfer = vAno
AND Aluno.CPFAluno = Registro.CPFAluno
AND Registro.NumReg = Matricula.NumReg
AND Matricula.NumOfer = Oferecimento.NumOfer
AND Oferecimento.NumCurso = Curso.NumCurso;
RETURN(MediaPonderada);
EXCEPTION
WHEN No_Data_Found THEN
RETURN(NULL);
WHEN OTHERS THEN
raise_application_error(-20001, 'Database error');
END;
/
-- Código de teste
SET SERVEROUTPUT ON;
DECLARE
vMedia DECIMAL(3,2);
BEGIN
-- Essa chamada deve mostrar uma média ponderada.
vMedia := fn_CalcularMediaPonderada('901-23-4567', 2006);
IF vMedia IS NULL THEN
dbms_output.put_line ('Aluno ou Matrículas não encontrados');
ELSE
dbms_output.put_line('Média ponderada é' || to_char(vMedia));
END IF;
-- Essa chamada não deve mostrar uma média ponderada.
vMedia := fn_CalcularMediaPonderada('905-23-4567', 2006);
IF vMedia IS NULL THEN
dbms_output.put_line('Aluno ou Matrículas não encontrados');
ELSE
dbms_output.put_line('Média Ponderada é' || to_char(vMedia));
END IF;
END;
/
-- Utiliza a função em uma consulta
SELECT CPFAluno, NomeAluno, SobrenomeAluno,
fn_CalcularMediaPonderada(CPFAluno, 2006) AS MediaPonderada
FROM Aluno;
Capítulo 11 Procedimentos Armazenados e Gatilhos 395
IF Encontrado THEN
RETURN(ClassTemp);
ELSE
RETURN(0);
END IF;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001, 'Database error');
END;
/
-- Código de teste
SET SERVEROUTPUT ON;
-- Executa uma consulta para ver os dados de teste
SELECT Aluno.CPFAluno, NotaMatr
FROM Aluno, Registro, Matricula
WHERE Matricula.NumOfer = 5679
AND Aluno.CPFAluno = Registro.CPFAluno
AND Registro.NumReg = Matricula.NumReg
ORDER BY NotaMatr DESC;
-- Script de teste
DECLARE
vClass INTEGER;
BEGIN
-- Essa chamada deve retornar uma classificação de 6.
vClass := fn_DeterminarClassificacao('789-01-2345', 5679);
IF vClass > 0 THEN
dbms_output.put_line('Classificação é' || to_char(vClass));
ELSE
dbms_output.put_line('Aluno não está matriculado.');
END IF;
-- Essa chamada deve retornar uma classificação de 0.
vClass := fn_DeterminarClassificacao('789-01-2005', 5679);
IF vClass > 0 THEN
dbms_output.put_line('Classificação é' || to_char(vClass));
ELSE
dbms_output.put_line('Aluno não está matriculado.');
END IF;
END;
/
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001, 'Database error');
END;
/
-- Código de teste
SET SERVEROUTPUT ON;
-- Executa uma consulta para ver os dados de teste
SELECT Aluno.CPFAluno, NotaMatr
FROM Aluno, Registro, Matricula
WHERE Aluno.CPFAluno = Registro.CPFAluno
AND Registro.NumReg = Matricula.NumReg
AND Matricula.NumOfer = 5679
ORDER BY NotaMatr DESC;
-- Script de teste
DECLARE
vClass INTEGER;
vNota Matricula.NotaMatr%TYPE;
BEGIN
-- Essa chamada deve produzir uma classificação de 6.
pr_DeterminarClassificacao('789-01-2345', 5679, vClass, vNota);
IF vClass > 0 THEN
dbms_output.put_line('Classificação é' || to_char(vClass) || '.');
dbms_output.put_line('Nota é ' || to_char(vNota) || '.');
ELSE
dbms_output.put_line('Aluno não está matriculado.');
END IF;
-- Essa chamada deve produzir uma classificação de 0.
pr_DeterminarClassificacao('789-01-2005', 5679, vClass, vNota);
IF vClass > 0 THEN
dbms_output.put_line('Classificação é' || to_char(vClass) || '.');
dbms_output.put_line('Nota é ' || to_char(vNota) || '.');
ELSE
dbms_output.put_line('Aluno não está matriculado.');
END IF;
END;
/
O PL/SQL oferece suporte a inúmeros atributos de cursor, assim como mostra a Tabela
11.5. Quando utilizado com um cursor explícito, o nome do cursor precede o atributo de cur-
sor. Quando utilizado com um cursor implícito, a palavra-chave do SQL precede o atributo de
cursor. Por exemplo, SQL%RowCount denota a quantidade de linhas em um cursor implícito.
O nome do cursor implícito não é utilizado.
TABELA 11.5
Atributo de Cursor Valor
Lista de Atributos
Comuns de Cursor %IsOpen Verdadeiro se o cursor estiver aberto
%Found Verdadeiro se o cursor não estiver vazio depois de uma instrução FETCH
%NotFound Verdadeiro se o cursor estiver vazio depois de uma instrução FETCH
%RowCount Número de linhas recuperadas. Depois de cada FETCH, RowCount é
incrementado.
CLOSE CursorMatr;
IF Encontrado THEN
ClassExt := ClassTemp;
NotaExt := PrevNotaMatr;
ELSE
ClassExt := 0;
NotaExt := 0;
END IF;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001, 'Database error');
END pr_DeterminarClassificacao;
FUNCTION fn_CalcularMediaPonderada
(vCPFAluno IN Aluno.CPFAluno%TYPE, vAno IN Oferecimento.AnoOfer%TYPE)
RETURN NUMBER IS
-- Computa a média ponderada dado o número do CPF de um aluno e o ano.
-- Média ponderada é a soma das cargas horárias multiplicada pela nota
-- dividida pelas cargas horárias totais.
-- Se o aluno não existe, retorna nulo.
MediaPonderada NUMBER;
BEGIN
SELECT SUM(NotaMatr*CargaHoraCurso)/SUM(CargaHoraCurso)
INTO MediaPonderada
FROM Aluno, Registro, Matricula, Oferecimento, Curso
WHERE Aluno.CPFAluno = vCPFAluno
AND Oferecimento.AnoOfer = vAno
AND Aluno.CPFAluno = Registro.CPFAluno
AND Registro.NumReg = Matricula.NumReg
AND Matricula.NumOfer = Oferecimento.NumOfer
AND Oferecimento.NumCurso = Curso.NumCurso;
RETURN(MediaPonderada);
EXCEPTION
WHEN no_data_found THEN
RETURN(NULL);
WHEN OTHERS THEN
raise_application_error(-20001, 'Database error');
END fn_CalcularMediaPonderada;
END pck_Universidade;
/
11.3 Gatilhos
Gatilhos (triggers) são regras gerenciadas por um SGBD. Como o gatilho envolve um evento,
gatilho uma condição e uma seqüência de ações, ele também é conhecido como regra evento-con-
uma regra que é armazenada
e executada por um SGBD.
dição-ação. A escrita da parte de ação ou do corpo do gatilho é semelhante à escrita de um
Como um gatilho envolve procedimento ou uma função, exceto que o gatilho não possui parâmetros. Os gatilhos são
um evento, uma condição executados pelo sistema de regras do SGBD e não por chamadas explícitas como nos pro-
e uma seqüência de ações, cedimentos e nas funções. Os gatilhos tornaram-se oficialmente parte do SQL:1999 embora
também é conhecido como a maioria dos fornecedores de SGBD houvesse implementado gatilhos bem antes do lança-
regra evento-condição-ação. mento do SQL:1999.
Esta seção trata dos gatilhos do Oracle com noções de gatilhos do SQL:2003. Na
primeira parte desta seção, serão discutidas as razões por que os gatilhos são parte importante
do desenvolvimento de aplicações de banco de dados e será introduzida a classificação dos
gatilhos. Na segunda parte, será mostrada a codificação de gatilhos em PL/SQL. Na parte
final, serão apresentados os procedimentos de execução de gatilhos do Oracle e SQL:2003.
Uma alternativa de gatilho para uma restrição complexa é a asserção discutida no Capí-
tulo 14. No entanto, a maioria dos SGBDs não oferece suporte a asserções, assim, os
gatilhos são a única escolha para restrições de integridade complexas.
• Restrições de transição: restrições de integridade que comparam os valores antes e de-
pois de uma atualização. Por exemplo, pode-se escrever um gatilho para impor uma res-
trição de transição, limitando os aumentos salariais em, no máximo, 10%.
• Propagação de atualização: colunas derivadas de atualização em tabelas relacionadas,
por exemplo, para manter o saldo de estoque permanente ou os assentos livres em um
vôo programado.
• Relatório de exceção: cria um registro de condições incomuns como alternativa para re-
jeitar uma transação. O gatilho também pode enviar uma notificação em uma mensagem
de correio eletrônico. Por exemplo, em vez de rejeitar o aumento salarial de 10%, o gatilho
pode criar um registro de exceção e notificar o gestor para rever o aumento salarial.
• Trilha de auditoria: cria o registro histórico de uma transação, por exemplo, o histórico
de utilização do caixa automático.
O SQL:2003 classifica os gatilhos por granularidade, momento de disparo e evento
aplicável. Em termos de granularidade, o gatilho pode envolver cada linha afetada por uma
instrução do SQL ou uma instrução inteira do SQL. Os gatilhos de linha são mais comuns que
os de instrução. Em termos de momento de disparo, o gatilho pode ser disparado antes ou de-
pois do evento. Normalmente, os gatilhos para verificação de restrições são disparados antes
de um evento, enquanto os gatilhos de atualização de tabelas e execução de outras ações são
disparados depois de um evento. Em termos de evento aplicável, o gatilho pode ser aplicado
a instruções INSERT, UPDATE e DELETE. Os gatilhos de atualização podem especificar
uma lista de colunas aplicáveis.
Como a especificação de gatilhos do SQL:1999 foi definida em resposta às implemen-
tações dos fornecedores, a maioria das implementações de gatilho varia da especificação
original do SQL:1999 à especificação revisada do SQL:2003. O Oracle tem suporte para a
maioria das partes da especificação, acrescentando, ao mesmo tempo, extensões proprie-
tárias. Uma extensão importante é o gatilho INSTEAD OF, disparado em lugar de um evento,
e não antes ou depois de um evento. O Oracle também tem suporte a eventos de definição de
dados e outros eventos de banco de dados. O Microsoft SQL Server fornece gatilhos de ins-
trução com acesso a dados da linha em vez de gatilhos de linha. Assim, a maioria dos SGBDs
oferece suporte ao espírito da especificação de gatilhos do SQL:2003 em termos de granu-
laridade, momento de disparo e eventos aplicáveis, mas não aderem estritamente à sintaxe de
gatilhos do SQL:2003.
EXEMPLO 11.22 Gatilho Disparado para Instrução INSERT na Tabela Curso Juntamente com o
Código de Teste para Disparar o Gatilho
CREATE OR REPLACE TRIGGER tr_Curso_IA
AFTER INSERT
ON Curso
FOR EACH ROW
BEGIN
-- Nenhuma referência à linha OLD porque existe somente NEW para INSERT
dbms_output.put_line('Linha Inserida');
dbms_output.put_line('NumCurso: ' || :NEW.NumCurso);
dbms_output.put_line('Descrição Curso: ' || :NEW.DescrCurso);
dbms_output.put_line('Carga Horária Curso: ' || To_Char(:NEW.CargaHora-
Curso));
END;
/
-- Instruções de teste
SET SERVEROUTPUT ON;
INSERT INTO Curso (NumCurso, DescrCurso, CargaHoraCurso)
VALUES ('SI485','Gerenciamento de Banco de Dados Avançado',4);
ROLLBACK;
Capítulo 11 Procedimentos Armazenados e Gatilhos 405
EXEMPLO 11.23 Gatilho Disparado para Toda Instrução UPDATE na Tabela Curso Juntamente
com o Código de Teste para Disparar o Gatilho
CREATE OR REPLACE TRIGGER tr_Curso_UA
AFTER UPDATE
ON Curso
FOR EACH ROW
BEGIN
dbms_output.put_line('Novos Valores de Linha');
dbms_output.put_line('NumCurso: ' || :NEW.NumCurso);
dbms_output.put_line('Descrição Curso:' || :NEW.DescrCurso);
dbms_output.put_line('Carga Horária Curso: ' || To_Char(:NEW.CargaHora-
Curso));
dbms_output.put_line('Valores Antigos de Linha');
dbms_output.put_line('NumCurso: ' || :OLD.NumCurso);
dbms_output.put_line('Descrição do Curso: ' || :OLD.DescrCurso);
dbms_output.put_line('Carga Horária do Curso: ' || To_Char(:OLD.CargaHora-
Curso));
END;
/
-- Instruções de teste
SET SERVEROUTPUT ON;
-- Adiciona linha de forma que possa ser atualizada
INSERT INTO Curso (NumCurso, DescrCurso, CargaHoraCurso)
VALUES ('SI485','Gerenciamento de Banco de Dados Avançado',4);
UPDATE Curso
SET CargaHoraCurso = 3
WHERE NumCurso = 'SI485';
ROLLBACK;
EXEMPLO 11.24 Gatilho Disparado para Toda Instrução DELETE na Tabela Curso Juntamente com
o Código de Teste para Disparar o Gatilho
CREATE OR REPLACE TRIGGER tr_Curso_DA
AFTER DELETE
ON Curso
FOR EACH ROW
BEGIN
-- Nenhuma referência à linha NEW porque existe somente OLD para DELETE
dbms_output.put_line('Linha Excluída');
dbms_output.put_line('NumCurso: ' || :OLD.NumCurso);
dbms_output.put_line('Descrição do Curso: ' || :OLD.DescrCurso);
dbms_output.put_line('Carga Horária do Curso: ' || To_Char(:OLD.Carga-
HoraCurso));
END;
/
-- Instruções de teste
SET SERVEROUTPUT ON;
-- Insere linha de forma que possa ser excluída
INSERT INTO Curso (NumCurso, DescrCurso, CargaHoraCurso)
VALUES ('SI485','Gerenciamento de Banco de Dados Avançado',4);
406 Parte Cinco Desenvolvimento de Aplicação com Bancos de Dados Relacionais
EXEMPLO 11.25 Gatilho com Evento Combinado, Disparado para Toda Ação na Tabela Curso
Juntamente com o Código de Teste para Disparar o Gatilho
CREATE OR REPLACE TRIGGER tr_Curso_DIUA
AFTER INSERT OR UPDATE OR DELETE
ON Curso
FOR EACH ROW
BEGIN
dbms_output.put_line('Tabela Incluída');
dbms_output.put_line('NumCurso: ' || :NEW.NumCurso);
dbms_output.put_line('Descrição do Curso: ' || :NEW.DescrCurso);
dbms_output.put_line('Carga Horária do Curso: ' || To_Char(:NEW.Carga-
HoraCurso));
dbms_output.put_line('Tabela Excluída');
dbms_output.put_line('NumCurso: ' || :OLD.NumCurso);
dbms_output.put_line('Descrição do Curso: ' || :OLD.DescrCurso);
dbms_output.put_line('Carga Horária do Curso: ' || To_Char(:OLD.Carga-
HoraCurso));
END;
/
-- Instruções de teste
SET SERVEROUTPUT ON;
INSERT INTO Curso (NumCurso, DescrCurso, CargaHoraCurso)
VALUES ('SI485','Gerenciamento de Banco de Dados Avançado',4);
UPDATE Curso
SET CargaHoraCurso = 3
WHERE NumCurso = 'SI485';
DELETE FROM Curso
WHERE NumCurso = 'SI485';
ROLLBACK;
Os gatilhos, diferentemente dos procedimentos, não podem ser testados diretamente. Em vez
disso, utilizam instruções do SQL que fazem o gatilho disparar. Quando o gatilho do Exem-
plo 11.25 é disparado para uma instrução INSERT, os antigos valores são nulos. Do mesmo
modo, quando o gatilho é disparado para uma instrução DELETE, os novos valores são nulos.
Quando o gatilho é disparado para uma instrução UPDATE, os valores antigos e novos não
são nulos a menos que a tabela tenha valores nulos antes da atualização.
Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar.
Exercícios
1) O que é procedure?
3) O que é um trigger?
Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar.
Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar.
Aponte a câmera para o código e acesse o link do conteúdo ou clique no código para acessar.