Fundamentos de Bancos de
Dados
José Maria Monteiro
Departamento de Computação
Universidade Federal do Ceará
Sumário
Stored Procedures;
Triggers;
Stored Procedures
Coleção de comandos SQL
Mecanismo semelhante ao RPC Código sob o controle do SGBD Passagem de parâmetros
Desempenho melhor por estar
“mais próximo” dos dados
Diminui tráfego de rede
Aplicação Stored Procedures exec procedure retorna resultado
Stored Procedures
Funções
Regras de negócio e integridade dos dados no SGBD Administração do sistema
Lado “servidor” da lógica da aplicação
Características
Comandos SQL compartilhados por aplicações Melhor desempenho em ambientes C/S
Stored Procedures
Menor flexibilidade
Pode piorar desempenho se o plano de execução
não for periodicamente refeito
Cada procedure é por default uma transação
separada
Falta de padronização/portabilidade!!!
Triggers
insert update delete Eventos Ação Comando SQL Stored Procedure SGBD ativo Reação automática a eventos monitoradosTriggers
Usar 650 parafusos “estoque de parafusos: 850” parafusos 1500 850 Se quantidade de parafusos em estoque é menor que 1000, então “acordar” comprador= > comprar 1000
Trigger - Exemplo
DEFINE TRIGGER Departamentos D, Empregados E,
Empregados G:
WHERE E.Salario > G.Salario AND E.CDep = D.Codigo AND
D.Gerente = G.CPF
ACTION_PROCEDURE(NOTIF_GERENTE(D.Gerente); Notificar o gerente se qualquer empregado do seu
Postgres
Diferente dos outros SGBDs:
Store Procedures e triggers são tratados como funções. Presença de diversas linguagens procedurais para
programação de funções diretamente no banco de dados.
Qual a vantagem de utilizar PL/pgSQL?
Praticidade da utilização de comandos SQLs integrados à
linguagem e na criação de cache dessas consultas.
Oficialmente distribuidas com o servidor:
PL/pgSQL, PL/TCL, PL/Python e PL/Perl. Podem ser instaladas:
PL/Java, PL/Ruby, PL/R.
Flexibilidade obtida separando o mecanismo do banco de
dados do executor das funções.
PL/pgSQL
Executa comandos SQL diretamente no corpo dos
procedimentos.
Segura, ambiente de execução é restrito ao SGBD. Uso de cache otimizado.
A programação é feita em blocos:
DECLARE
... Declaração de Variáveis BEGIN
... Comando PL/pgSQL END
PL/pgSQL
IF condição 1 THEN
Seqüência de comandos 1 ELSIF condição 2 THEN
Seqüência de comandos 2 ELSE
Seqüência de comandos 3 END IF;
PL/pgSQL
LOOP Seqüência de comandos END LOOP; Estruturas de Controle
LOOP IF condição THEN Seqüência de comandos EXIT; END IF; END LOOP;PL/pgSQL
WHILE condição LOOP
Seqüência de comandos END LOOP;
Estruturas de Controle
FOR contador IN
[REVERSE] X..Y LOOP
Seqüência de comandos END LOOP;
PL/pgSQL
Tratamento de Exceção:
RAISE NOTICE ‘%’, var ; (mensagem)
RAISE NOTICE ‘Texto qualquer’;
PL/pgSQL
Custo é alto, usar somente se necessário
Bloco de Exceção:
BEGIN comandos
EXCEPTION WHEN condição THEN comandos de tratamento
WHEN condição THEN comandos de tratamento END;
PL/pgSQL
Funções armazenadas (“stored procedures”)
Triggers
PL/pgSQL
Funções armazenadas:
CREATE FUNCTION atualizaValor ( valor varchar ) RETURNS boolean
CREATE [ OR REPLACE ] FUNCTION
name ( [ [ argname ] argtype [, ...] ] ) RETURNS rettype
Onde rettype pode ser :
1. Tipo primitivo
2. Estrutura composta 3. Tipo do domínio
Funções armazenadas:
PL/pgSQL
CREATE FUNCTION primeira_funcao() RETURNS VOID AS $body$ BEGIN RETURN; END; $body$ LANGUAGE 'plpgsql';
Imprime a mensagem “Minha primeira rotina em
PL/pgSQL”:
Exemplo PL/pgSQL
CREATE OR REPLACE FUNCTION primeira_funcao() RETURNS VOID AS
$body$ BEGIN
RAISE NOTICE 'Minha primeira rotina em PL/pgSQL'; RETURN;
END; $body$
LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION primeira_funcao() RETURNS VOID AS
$body$ BEGIN
RAISE NOTICE 'Minha primeira rotina em PL/pgSQL'; RETURN;
END; $body$
Executando uma FUNCTION
Exemplo PL/pgSQL
select primeira_funcao()
PL/pgSQL
Declarando variáveis:
Atribuindo valores: numero := 15; Declarando variáveis: DECLAREPL/pgSQL
Executando SQL:
CREATE OR REPLACE FUNCTION exclui_cliente(pid_cliente Integer) RETURNS Integer
AS $body$ DECLARE
vLinhas Integer DEFAULT 0; BEGIN
DELETE FROM clientes WHERE id_cliente = pid_cliente; GET DIAGNOSTICS vLinhas = ROW_COUNT;
RETURN vLinhas; END;
$body$
Executando uma FUNCTION
select exclui_cliente(3)
select exclui_cliente(3)
PL/pgSQL
CREATE OR REPLACE FUNCTION media_compras(pid_cliente Integer) RETURNS numeric AS $body$ DECLARE linhaCliente Clientes%ROWTYPE; mediaCompras real; totalCompras real; periodo Integer; BEGIN
SELECT * INTO linhaCliente FROM clientes WHERE id_cliente = pid_cliente; periodo := age(current_date, linhaCliente.data_inclusao);
SELECT SUM(valor_total) INTO totalCompras FROM pedidos WHERE id_cliente = pid_cliente;
mediaCompras := totalCompras / periodo; RETURN mediaCompras;
END;
$body$ LANGUAGE 'plpgsql';
Variável armazena uma linha da tabela Clientes
Variável armazena resultado da consulta Atribuição
Exemplo
Na tabela Aluno
Criar função armazenada ( “stored procedure”)
para atualizar o valor currículo do aluno.
Parâmetros
valor novo para currículo Num_matricula
CREATE FUNCTION atualizaCurriculo(varchar valorNovo, varchar mat) RETURNS boolean AS
$$
BEGIN
UPDATE aluno SET curriculo = $1 WHERE num_matricula = $2;
RETURN FOUND; END;
$$
LANGUAGE 'plpgsql' ;
CREATE FUNCTION atualizaCurriculo(varchar valorNovo, varchar mat) RETURNS boolean AS
$$
BEGIN
UPDATE aluno SET curriculo = $1 WHERE num_matricula = $2; RETURN FOUND; END; $$ LANGUAGE 'plpgsql' ; $1, $2 são parâmetros passados pela chamada da função
palavra reservada do sistema; booleano que retorna true sse houve alteração
PL/pgSQL
Cursor:
Áreas de memória utilizadas pelo PostgreSQL para
armazenar registros enquanto eles são processados.
Usados para percorrer as relacões e processar
conjuntos de dados.
Criada por resultado de COMMIT, ROLLBACK,
INSERT, SELECT , UPDATE, DELETE
PL/pgSQL
cursor1 refcursor
(30) ;
cursor2 CURSOR FOR
SELECT * FROM tab1 ;
cursor3 CURSOR (chave integer) IS SELECT *
FROM tab1
WHERE unique1 = chave;
cursor1
refcursor;
Uso do cursor
1.
Declarar ( declare )
2.Abrir ( open )
3.
Navegar/ Atribuir os valores ( fetch )
4.Fechar ( close )
* Postgres: invocação de função com cursor
deve ocorrer dentro de transação
PL/pgSQL
OPEN FOR SELECT
OPEN FOR EXECUTE
Abrir cursor:
OPEN cursor FOR SELECT query ;
OPEN cursor FOR EXECUTE
Abrir cursor para SELECT
Cursor sem limite ( cursor refcursor )
create function cursorLerAluno(varchar) returns text as $$ declare c refcursor; nm aluno.nome%type; cur aluno.curriculo%type; begin
OPEN c FOR SELECT nome, curriculo from aluno where num_matricula = $1;
fetch c into nm, cur; close c;
return nm || ','|| cur; end;
$$ language 'plpgsql';
Abrir cursor para EXECUTE
Cursor sem limite
Palavra reservada EXECUTE
EXECUTE pede string ( usar apóstrofo ) Situações de SQL dinâmico ( passagem dos
parâmetros como tabela , comando )
Pode-se usar uma variável que armazena o
create or replace function cursorLerAluno(varchar) returns text as $$ declare c refcursor; nm aluno.nome%type; cur aluno.curriculo%type; begin
OPEN c FOR EXECUTE 'SELECT nome, curriculo from aluno where num_matricula ='|| $1;
fetch c into nm, cur; close c;
return nm || ','|| cur; end;
$$
language 'plpgsql';
PL/pgSQL
FETCH direction [ count ] { IN | FROM } cursor
direction ::= { FORWARD | BACKWARD |
RELATIVE }
count ::= { numrows | ALL | NEXT | PRIOR }
FETCH Cursor:
create or replace function teste() returns boolean as $body$ declare c refcursor; reg aluno%rowtype; i integer; tot integer; begin
OPEN c FOR SELECT * from aluno ; SELECT count(*) INTO tot from aluno; i:=1;
FOR i IN 1..tot LOOP FETCH c INTO reg;
raise notice '%', reg.nome ;
raise notice '%', reg.num_matricula ; END LOOP; close c; RETURN FOUND; end; $body$ language 'plpgsql‘;
FETCH Cursor
CREATE OR REPLACE FUNCTION cursor_empregado() RETURNS void AS $BODY$
DECLARE
cursor1 CURSOR IS SELECT * FROM EMPREGADO; emp empregado%ROWTYPE;
BEGIN
open cursor1;
fetch cursor1 into emp; loop
exit when not found;
RAISE NOTICE ‘Empregado de id: %‘, emp.id; fetch cursor1 into emp;
end loop; close cursor1; END; $BODY$ LANGUAGE 'plpgsql' VOLATILE ;
PL/pgSQL
Declara a váriávelcursor Abre o cursor
Coloca a próxima linha do cursor na váriável
Triggers (Gatilhos)
Função trigger pode ser escrita em C ou em
qualquer outra linguagem procedural.
Iremos utilizar o PL/pgSQL.
Função trigger é uma função declarada sem
argumentos e retorna um tipo de dados trigger.
Uma mesma função trigger pode ser utilizada
em vários triggers.
Um trigger só pode ser definido depois que a
sua função trigger já estiver criada.
Postgres
Triggers (Gatilhos)
Ele é invocado (disparado) quando ocorre uma
tentativa de modificação nos dados da tabela (relação) à qual ele está associado (vinculado).
Os triggers podem ser invocados por cada
linha afetada ou por cada comando INSERT, UPDATE ou DELETE.
Podem ser definidos para executar antes ou
depois de qualquer modificação no banco de dados.
Postgres
Triggers (Gatilhos)
Os triggers são usados para garantir regras de
negócio e integridade dos dados, ou para ações complexas, tais como automaticamente atualizar um resumo dos dados.
Caso a execução de um trigger possa violar
alguma restrição, então ele não será executado.
Exemplo Triggers PL/pgSQL
Suponha duas tabelas: Estudante e Exame. Estudantes fazem exames.
Não utilizamos FOREIGN KEY na tabela
Exame.
Escreva uma função trigger para forçar uma
restrição de integridade entre as tabelas Exame e Estudante.
Estudante(mat integer, nome varchar(20)) Exame(eid integer, enome varchar(15))
Criação das tabelas
CREATE TABLE Estudante (mat INTEGER, name VARCHAR(20));
CREATE TABLE Exame (eid INTEGER, enome VARCHAR(20));
Função trigger escrita em PL/pgSQL
CREATE OR REPLACE FUNCTION restr_integr()RETURNS trigger AS ‘
DECLARE estudantes RECORD; BEGIN
SELECT * INTO estudantes FROM Estudante WHERE NEW.mat = mat; IF NOT FOUND THEN
RAISE NOTICE \’Estudante inexistente! %\’, NEW.mat; RETURN NULL; ELSE RETURN NEW; END IF; END; ‘ LANGUAGE ‘PLpgSQL’;
Criação do Trigger
CREATE TRIGGER rest_trigger
BEFORE INSERT ON Exame
FOR EACH ROW
Entendendo a síntaxe...
CREATE OR REPLACE: Sem este comando, ao modificar
a definição de uma função, você deve removê-la primeiro.
AS ‘ ... ‘ : O corpo da função deve estar entre as aspas
simples.
DECLARE estudante RECORD: a variável estudante pode
armazenar uma informação de uma linha.
NEW.mat: Como o trigger é antes do INSERT, NEW
corresponde a nova linha a ser inserida.
RAISE NOTICE: Usado para mostrar um erro.
RETURN NULL: Skip a inserção da tupla.
Inserir tuplas…
Inserir os seguintes estudantes:
Insert INTO Estudante VALUES (1,’José’); Insert INTO Estudante VALUES (2,’João’);
Ao tentar inserir na tabela de Exames, como o
estudante de mat=1 já existe, o trigger deverá permitir a inserção:
Já a seguinte inserção, na tabela Exame não deve
ser permitida:
Agora, tente inserir em Exame...
Insert INTO Exame VALUES (1,’FBD I’);
declare
dataFrequencia char(20);
timestampFrequencia timestamp;
dataFrequencia = ano || '-' || mes || '-' || dia;
timestampFrequencia = CAST (dataFrequencia AS timestamp);
now();
date_part(year, freq_data); CAST ($2 AS character);
timestampFrequencia = CAST ('2009-11-' || diaFrequencia AS timestamp);
CAST (date_part('month', freq_data) as integer);