Você está na página 1de 59

BD II (SI 587)

Procedimentos Armazenados

Josenildo Silva
jcsilva@ifma.edu.br
MOTIVAÇÃO
Contexto: Sistemas em 2 camadas
Contexto: Sistemas em 3 camadas
Problema 1: Alto volume de dados na rede
Como reduzir o tráfego na rede?

Exemplo 1

Select SUM(qtd) as total from


produto group by codProd;
...
Para cada produto
se total < 10% do estoque
então
insert into OrdemCompra ...
Problema 1: Alto volume de dados na rede
Como reduzir o tráfego na rede?

Exemplo 2

Realizar a sequência
Insert into VENDA ...
Insert into NOTAFISCAL ...
Update ESTOQUE ...
para cada venda.
Problema 1: Alto volume de dados na rede
Como reduzir o tráfego na rede?

Exemplo 3

Realizar a sequência
Insert into PESSOA ...
Insert into ALUNO ...

para cada entidade em uma hierarquia


de generalização/especialização.
Problema 1: Alto volume de dados na rede

Entretanto ...
O gargalo pode ser provocado pelo
próprio servidor de banco de dados.
Caberá ao desenvolvedor, em
conjunto com o DBA, identificar
cada caso.
Problema 2: Manutenção

Como garantir consistência de regras de negócio


nas diversas aplicações e módulos clientes?
Ou seja

Algumas situações reais em grandes


sistemas
Comandos repetitivos com lógica complexa

Várias linguagens de programação envolvidas

Rotinas periódicas

Todas estas situações podem se beneficiar


com o uso de procedimentos armazenados.
PROCEDIMENTOS ARMAZENADOS
Procedimentos Armazenados

São funções (rotinas) definidas no banco


de dados, identificadas por um nome pelo
qual podem ser invocadas.
Um procedimento pode executar várias
instruções, receber parâmetros e retornar
valores
Quando utilizar?

Quando aplicações em diferentes


linguagens, ou plataformas diferentes,
executando a mesma função.
Quando utilizar?

Exemplo: Os bancos (Itaú, Bradesco, etc),


em geral, utilizam procedures para todas as
operações em comum.
Por que utilizar?

Otimização: redução de tráfego de dados


entre aplicação e o SGBD
Segurança: utilizando procedures o acesso
às tabelas do banco de dados acontece de
forma indireta
Manutenção: reuso do mesmo código em
diversas aplicações
Desvantagens

Necessidade de maior conhecimento da


sintaxe do banco de dados para escrita de
rotinas em SQL
A sintaxe muda de um banco para outro

As rotinas ficam mais facilmente acessíveis


Alguém que tenha acesso ao banco poderá visualizar e
alterar o código.
SQL/PSM
Procedimentos armazenados SQL/PSM

Procedimentos armazenados
Módulos de programa armazenados pelo SGBD no
servidor de banco de dados
Podem ser funções ou procedimentos

SQL/PSM (Persistent Stored Modules)


Extensões à SQL (publicado em 1996)
Inclui construções de programação de uso geral em SQL
Sintaxe para Procedimentos

CREATE PROCEDURE <nome> (<params>)


<declarações de variáveis locais>

<corpo do procedimento> ;
Sintaxe para Funções

CREATE FUNCTION <nome> (<params>)


RETURNS <tipo de retorno>

<declarações de variáveis locais>

<corpo da função> ;
Parâmetros

Cada parâmetro deve ter:


Tipo: um dos tipos de dados da SQL

Modo: IN, OUT ou INOUT

Parâmetros IN são o padrão, pode-se omiti-


lo após o nome
Chamando procedimentos e funções

No Mysql
CALL <nome do proc ou func>(<args>) ;

No Oracle
BEGIN
<nome do proc ou func>(<args>) ;
END
Comando de Controle (IF)

IF <condicao> THEN <lista de instrucoes>


ELSEIF <condicao> THEN <lista de instrucoes>
...
ELSEIF <condição> THEN <lista de instrucoes>
ELSE <lista de instrucoes>
END IF ;
Comando de Controle Laço (WHILE)
Comando de Controle Laço (FOR)
Exemplo
SQL/PSM NO MYSQL 5.0
Cenário 1 (cont.)

Sistemas de venda sem SQL/PSM


O cliente faz um pedido, no qual são
inseridos itens.
O pedido (bem como os itens) permanece
com status “PENDENTE” até ser confirmado.
Cenário 1
Até o pedido ser confirmado, nenhum
lançamento é feito no livro caixa
Após a confirmação fazer as ações:
Atualizar o status do pedido;
Atualizar o status dos itens do pedido;
Lançar o valor do pedido no caixa.

Esta regra de negócio tem que ser replicada


em todos os front-end (web, desktop, etc)
Cenário 1
Cenário 2

Sistemas de venda com SQL/PSM


As ações de update/insert/delete são
agrupadas em uma procedure no servidor
Sintaxe de procedures no mysql
DELIMITER $$
CREATE PROCEDURE nome_proc (parâmetros)
BEGIN
/*CORPO DO PROCEDIMENTO*/
END $$
DELIMITER ;

Delimitador é preciso inicialmente alterar o


delimitador padrão do MySQL (por exemplo $$) e
ao fim da criação do procedimento, restaurar seu
valor padrão
Exemplo 1: usando parâmetro de entrada
DELIMITER $$
CREATE PROCEDURE selecionar_prod(IN quantidade INT)
BEGIN
SELECT * FROM PRODUTOS
LIMIT quantidade;
END $$
DELIMITER ;

Para chamar este procedimento


CALL selecionar_prod(2);
Exemplo 2: usando parâmetro de saída
Armazena o total de
produtos
DELIMITER $$

CREATE PROCEDURE Quantidade_Produtos(OUT quantidade INT)


BEGIN
SELECT COUNT(*) INTO quantidade FROM PRODUTOS;
END
$$
DELIMITER ;

CALL Quantidade_Produtos(@total);

SELECT @total;
a variável poderá ser usada
posteriormente
Exemplo 3: parâmetro de entrada e saída

DELIMITER $$

CREATE PROCEDURE metada(INOUT numero INT)


BEGIN
SET numero = numero / 2;
END $$
DELIMITER ;

SET @valor = 10;


CALL metade(@valor);
SELECT @valor;

a variável poderá ser usada


posteriormente
Variáveis no corpo do procedimento

DECLARE nome_var TIPO [DEFAULT valor];

Exemplos
DECLARE quantidade int DEFAULT 0;

DECLARE valor decimal(9,2);

DECLARE total_valor decimal(9,2);

DECLARE done INT DEFAULT FALSE;


Cursores no MySQL

Itera um conjunto de tuplas


Utiliza-se dentro de uma procedure,
function ou triggers
Sintaxe
DECLARE nome FOR (SELECT ...)
Usando Cursores no MySQL
OPEN nome
para abrir o cursor , que fará com que ele executea
consulta;
Logo em seguida inicia o loop com a seguinte instrução
– nome_cursor : loop

FETCH nome INTO


para atribuir o retorno do cursor a uma ou mais
variáveis;

CLOSE nome
Exemplo de Cursor no MySQL
CREATE PROCEDURE cursordemo()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE a CHAR(16);
DECLARE b, c INT;
DECLARE cur1 CURSOR FOR SELECT id,data FROM t1;
DECLARE cur2 CURSOR FOR SELECT i FROM t2;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
OPEN cur2;
read_loop: LOOP
FETCH cur1 INTO a, b;
FETCH cur2 INTO c;
IF done THEN
LEAVE read_loop;
END IF;
IF b < c THEN
INSERT INTO test.t3 VALUES (a,b);
ELSE
INSERT INTO test.t3 VALUES (a,c);
END IF;
END LOOP;
CLOSE cur1;
CLOSE cur2;
END;

Fonte: http://dev.mysql.com/doc/refman/5.7/en/cursors.html
Cenário: controle de estoque

O vendedor deve verificar a disponibilidade


de um determinado produto em tempo real.
O setor de compras deve planejar melhor
as atividades de compra.
Cenário: controle de estoque
Não é recomendado inserir, atualizar e somente recebe os dados
excluir diretamente nesta tabela conforme as
ações executadas nas
tabelas de
ENTRADA e SAIDA de
Produto.

Registra as compras Registra as vendas


Procedure que atualiza o estoque
delimiter $$
create procedure pAtualizaEstoque(idProd int,
qtdeComprada int,
valorUnitario decimal(9,2) )
begin
declare existeProd int;
select id_produto into existeProd from estoque
where id_produto = idProd;
if (existeProd is not null) then
update estoque set qtde = qtde + qtdeComprada,
valor_unitario = valorUnitario
where id_produto = idProd;
else
insert into estoque (id_produto, qtde, valor_unitario)
values (idProd, qtdeComprada,valorUnitario);
end if;
end $$
delimiter ;
SQL/PSM NO ORACLE
Procedure no Oracle

DECLARE

// Coloque as variáveis aqui

BEGIN

// Aqui vai o código

EXCEPTION

// Tratamento de erros

END;
Procedure no Oracle

declare
media INT := 10;
begin
select avg(SALARY) into media from EMPLOYEES;
DBMS_OUTPUT.PUT_LINE(‘Media:’|| TO_CHAR(media) );
end;
Procedure no Oracle

CREATE [OR REPLACE] PROCEDURE <nome>


[ (par1 type1, par2 type2,...) ]
IS | AS
DECLARE
....
BEGIN
...
EXCEPTION
...
END <name>;
Exemplo de Procedure no Oracle

CREATE OR REPLACE PROCEDURE PDate IS


BEGIN
DBMS_OUTPUT.PUT_LINE('DATE:'||TO_CHAR(SYSDATE));
END PDate;

Para fazer a chamada (execução) crie um


bloco simples:
BEGIN
PDate();
END;
Exemplo de Procedure com Parametro IN

CREATE OR REPLACE PROCEDURE PROC_ID(p_id


EMPLOYEES.EMPLOYEE_ID%TYPE) IS
BEGIN
UPDATE EMPLOYEES
SET LAST_NAME = LAST_NAME || ' X'
WHERE EMPLOYEE_ID = p_id;
COMMIT;
END PROC_ID;
Exemplo de Procedure com Parametro IN

-- Execução com parâmetros posicionais


BEGIN
PROC_ID(176);
END;
-- Execução com parâmetros nomeados
BEGIN
PROC_ID(p_id=>176);
END;
Efeito
SELECT * FROM EMPLOYEES
WHERE EMPLOYEE_ID = 176;
Exemplo de Procedure com parametro OUT

CREATE OR REPLACE PROCEDURE PROC_NAME(


p_id IN EMPLOYEES.EMPLOYEE_ID%TYPE,
p_name OUT EMPLOYEES.LAST_NAME%TYPE )
IS
BEGIN
SELECT LAST_NAME INTO p_name
FROM EMPLOYEES
WHERE EMPLOYEE_ID = p_id;
END PROC_NAME;
Exemplo de Procedure com parametro OUT

-- Execução
DECLARE
v_name varchar(100);
BEGIN
PROC_NAME(176,v_name);
DBMS_OUTPUT.PUT_LINE(Nome:'||TO_CHAR(v_name));
END;
Exemplo com parametros in out no Oracle

CREATE OR REPLACE PROCEDURE


PROC_CONCAT(P_CHAR IN OUT VARCHAR2 )
IS
BEGIN
P_CHAR:= '(' || P_CHAR || ')';
END PROC_CONCAT;
Procedure no Oracle

-- Execução
DECLARE
ret VARCHAR(100);
BEGIN
FOR emp_rec IN (SELECT LAST_NAME FROM EMPLOYEES )
LOOP
DBMS_OUTPUT.PUT_LINE(Nome: ' ||
TO_CHAR(emp_rec.LAST_NAME) );
PROC_CONCAT(emp_rec.LAST_NAME);
DBMS_OUTPUT.PUT_LINE(‘Nome: ' ||
TO_CHAR(emp_rec.LAST_NAME) );
END LOOP;
END;
Exemplo de parametro IN OUT

create or replace
procedure pAtualizaEstoque(
idProd ESTOQUE.ID%TYPE,
qtdeComprada ESTOQUE.QTDE%TYPE,
valorUnitario ESTOQUE.VALOR_UNITARIO%TYPE)
cont...
is
total number;
begin
select count(id_produto) into total
from estoque where id_produto = idProd;
if (total > 0) then
DBMS_OUTPUT.PUT_LINE('Antes de atualizar ....');
update estoque
set qtde = qtde + qtdeComprada,
valor_unitario = valorUnitario
where id_produto = idProd;
else
DBMS_OUTPUT.PUT_LINE('Antes de inserir ....');
insert into estoque (id, id_produto,
qtde, valor_unitario)
values (seq_idEstoque.nextval, idProd,
qtdeComprada, valorUnitario);
end if;
end pAtualizaEstoque;
Parametros default

create or replace procedure


proc_default(x int default 1)
is
begin
dbms_output.put_line('value: ' ||
to_char(x*1) );
end proc_default;
Parametros default

-- Execução
BEGIN
PROC_DEFAULT();
PROC_DEFAULT(3);
END;
Leitura Adicional

Seção 9.6 do SILBERSCHATZ: Funções e


Procedimentos
Tutorial sobre Procedimentos no MySQL por
Wagner Bianchi.
http://imasters.com.br/artigo/7556/mysql/stored
_procedures_no_mysql/
http://www.mysqltutorial.org/introduction-to-
sql-stored-procedures.aspx
Links interessantes
http://dev.mysql.com/doc/refman/5.1/en/stored-
routines.html

http://www.mysqltutorial.org

http://www.databasejournal.com/features/mysql/article.
php/3525581/MySQL-Stored-Procedures-Part-1.htm
http://www.oficinadanet.com.br/artigo/2088/criando_stored_pro
cedures_no_mysql

http://www.brainbell.com/tutorials/MySQL/Using_Store
d_Procedures.htm