Você está na página 1de 60

BD II (SI 587)

Procedimentos Armazenados

Josenildo Silva
jcsilva@ifma.edu.br
MOTIVAÇÃO
Contexto: Sistemas em 2 camadas

Cliente Cliente Cliente

SGBD
Contexto: Sistemas em 3 camadas

Cliente Cliente Cliente

Aplicação

SGBD
Problema 1: Alto volume de dados na rede
Como reduzir o tráfego na rede?
Cliente

Aplicação
Exemplo 1

Select SUM(qtd) as total from


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

Aplicação
Exemplo 2

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

Aplicação
Exemplo 3
Realizar a sequência
Insert into PESSOA ...
Insert into ALUNO ...

para cada entidade em uma


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

Cliente

Aplicação

Entretanto ...
O gargalo pode ser provocado pelo
próprio servidor de banco de dados.
Caberá ao desenvolvedor, em
SGBD
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?

Cliente (Java) Cliente (PHP) Cliente (Ruby)

Aplicação

SGBD
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
IFMA Monte Castelo
Depto. de Computação
Sistemas de Informação

Prof. Josenildo Silva


jcsilva@ifma.edu.br
@silvajc
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 metade(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

Seção 13.4 do NAVATHE: Procedimentos armazendados

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/My
SQL-Stored-Procedures-Part-1.htm

http://www.oficinadanet.com.br/artigo/2088/criando_stored_procedures_no_mysql

http://www.brainbell.com/tutorials/MySQL/Using_Stored_Procedures.htm

Você também pode gostar