Store Procedure
Estrutura procedural simples
Cada banco de dados decidiu criar uma liguagem extra para ter um mellhor controle de fluxo, e a porta para tudo isso foi as Store Procedures.
CREATE PROCEDURE nome_procedure
Parametros
BEGIN
DECLARE
- Variaveis, cursores, constantes, tabelas, estruturas e exceptions
- PL/SQL statements
END;
Regras de nomenclatura
- O nome da SP deve conter apenas letras e numeros, $ e _ para demarcar espaços
- Um tamanho máximo de 64 caracteres
- Deve ser nome único
- É case sensitive deve ser referenciada de maneira idêntica
Usando a Store Procedure
CALL nome_Sp;
Modelo pratico
USE `nomeBD`;
DROP procedure IF EXISTS `primeiro_procedure`;
DELIMITER $$ define delimitador para $$
USE `nomeBD`$$
CREATE PROCEDURE `primeiro_procedure` ()
BEGIN
SELECT 'hello world' as Mensagem; note que o delimitador interno continua sendo o ;
END$$
DELIMITER ;
Usando
CALL primeiro_procedure;
O Mesmo serve para alterar o comando, já que se existir ele apaga.
Para apagar é só usar o DROP procedure
sem delimitar outras configurações.
VARIAVEIS
DECLARE fica responsável por iniciar a variável sem seguida o nome da mesma, o tipo de dados e um valor padrão(opcional).
Regras de nomenclatura
- O nome da SP deve conter apenas letras e numeros, $ e _ para demarcar espaços
- Deve ser nome único
- Um tamanho máximo de 255 caracteres
- É case sensitive
- Se não declarar Default o valor da variável recebe NULL
- Termina com ;
- É possível declarar varias variáveis desde que tenham o mesmo tipo
Tipos
TIPO | definição |
---|---|
VARCHAR(n) |
Caracteres tipo texto com tamanho de n. |
INTEGER |
Variaveis tipo Inteiro. |
DECIMAL(i,f) |
Variavies decimais 'i' e a fração em 'f'. |
DATE |
Guarda data AAAA-MM-DD. |
TIMESTAMP |
Guarda data e hora AAAA-MM-DD HH-MM-SS. |
Modelo uso de Declare
DELIMITER $$
USE 'nome_bd'$$
CREATE procedure 'ver_variavel'()
BEGIN
declare texto char(15) default 'Hellow World';
declare numero decimal(6,3) default 999.666;
declare tempo datetime default localtimestamp;
SELECT texto;
SELECT numero;
SELECT tempo;
END $$
DELIMITER;
Múltiplas Variaveis
...
CREATE procedure 'ver_multiplos'()
BEGIN
declare num_1, num_2 int default 369;
SELECT num_1, num_2;
END$$
DELIMITER;
Alterando Valores
...
CREATE procedure 'ver_valor'()
BEGIN
declare num_1 int default 369;
SELECT num_1;
SET num_1 = 963;
SELECT num_1;
END$$
DELIMITER;
Entrada por procedure
DELIMITER $$
use `nome_bd`$$
create procedure `inclui_produto`()
begin
declare vNome varchar(45) default 'produto';
declare vPreco decimal(5,2) default '36.90';
insert into nome_tabela
(nome, preco)
value
(vNome, vPreco);
end$$
DELIMITER ;
call inclui_produto;
Parametros
Os parametros no PL/SQL se assemelha muito a funções em POO
...
CREATE PROCEDURE `produto_parametro`(vNome varchar(45), vPreco decimal(5,2))
BEGIN
INSERT INTO tabela
(nome, preco)
VALUES
(vNome, vPreco);
END$$
...
CALL produto_parametro( 'produto', 9.99);
Tratando erros e salvando retorno
Tratando erros
É possível ter um retorno mais amigável através da tratava erros.
O comando DECLARE EXIT
libera a execução do programa como um "break", HANDLER FOR
escuta o retorno, então referencie o codigo do erro logo após a declaração.
...
BEGIN
DECLARE aviso varchar(36);
DELCARE EXIT HANDLER FOR 1062
begin
set aviso = 'Chave repetida'
select aviso;
end;
INSERT INTO nome_tabela
(id_produto, nome, preco)
VALUES
(vId_produto, vNome, vPreco)
SET aviso = 'Produto incluido!';
SELECT aviso;
END$$
...
Salvando retorno
Para salvar um retorno basta referenciar a resposta com um INTO
seguido do nome da variavel que vai receber o valor, devidamente declarada.
...
CREATE PROCEDURE 'recebe_select'( vId_produto varchar (40))
BEGIN
DECLARE vProduto VARCHAR(45);
SELECT produto INTO vProduto FROM tabela WHERE id_produto = vId_produto;
SELECT vProduto ;
END$$
...
Controle de Fluxo
IF
Controle de fluxo com duas saídas possíveis, caso atenda os requisitos da condição e outro para caso não atenda.Estrutura básica;
IF condition THEN
if_statements;
ELSE
else_statements;
END IF
Modelo Pratico
create procedure `curso_nivel`(vId int)
begin
declare vResultado varchar (20);
declare vNivel int;
select NIVEL INTO vNivel from habilidades
where id_plano = vId;
if vNivel > 1 then
set vResultado = 'Intermediario';
else
set vResultado = 'Iniciante';
end if;
select vResultado;
end$$
create procedure `curso_nivel`(vId int)
begin
declare vResultado varchar (20);
declare vNivel int;
select NIVEL INTO vNivel from habilidades
where id_plano = vId;
if vNivel = 1 then
set vResultado = 'Iniciante';
elseif vNivel = 2 then
set vResultado = 'Intermediario';
else
set vResultado = 'Avançado';
end if;
select vResultado;
end$$
CASE
Controle de fluxo do de uma variavel versus uma lista de opções, atendido o requisito para algum dos itens listados um comando correspondente será disparado.
Estrutura básica;
CASE selector
WHEN selector_value_1 THEN then_statements_1;
WHEN selector_value_2 THEN then_statements_2;
WHEN ...
[ELSE else_statements]
END CASE;
Modelo pratico
create procedure `class_memoria`(vMATERIA varchar(36))
begin
declare vMemoria tinyint;
select SITUACAO_MEMORIA into vMemoria from metas
where MATERIA = vMATERIA;
CASE vMemoria
when 1 then select 'Boa' as condição de memoria;
when 2 then select 'Moderada' as condição de memoria;
when 3 then select 'Decaindo' as condição de memoria;
when 4 then select 'Esquecimento' as condição de memoria;
when 5 then select 'Vaga Lembrança' as condição de memoria;
else select 'Ainda não começou' as Sem memoria;
end case;
CASE ERRO
Podemos tratar um case sem ELSE
e comando alheio. O mesmo pode ter um retorno sem interromper o processo como no tratando erros.
Modelo pratico
create procedure `class_memoria`(vMATERIA varchar(36))
begin
declare vMemoria tinyint;
declare msgErro varchar (45);
declare continue handler for 1339 set msgErro = ''O case não tem retorno previsto para condição evidenciada.
select SITUACAO_MEMORIA into vMemoria from metas
where MATERIA = vMATERIA;
CASE vMemoria
when 1 then select 'Boa' as condição de memoria;
when 2 then select 'Moderada' as condição de memoria;
when 3 then select 'Decaindo' as condição de memoria;
when 4 then select 'Esquecimento' as condição de memoria;
when 5 then select 'Vaga Lembrança' as condição de memoria;
else select 'Ainda não começou' as Sem memoria;
end case;
SELECT msgErro;
end $$
Observação
O CASE
ainda pode ser utilizado no lugar do ELSEIF
para caso de grande linha de testes, uma vez que o ELSEIF
testa a variável com linha a linha e o CASE
testa apenas a condição correspondente.
Looping
Comandos que vão ser repetidos até que a condição seja satisfeita.
WHILE condition
DO statements;
END WHILE;
Modelo pratico
CREATE PROCEDURE `looping_while` (vNumInicial INT , vNumFinal INT)
BENGIN
DECLARE vContador INT;
DELETE FROM TAB_LOOPING;
SET vContador = vNumInicial;
área de rep WHILE vContador <= vNumFinal
DO
INSERT INTO TAB_LOOPING (ID) VALUES (vContador);
SET vContador = vContador + 1;
END WHILE;
SELECT * FROM TAB_LOOPING;
END
Cursores
Comandos que vão retornar uma array com todos os resultados.
DECLARE @nome;
DECLARE CURSOR_X CURSOR FOR;
SELECT NOME FROM TABELA;
OPEN CURSOR_X;
FETCH CURSOR_X; INTO @nome;
FETCH CURSOR_X; INTO @nome;
FETCH CURSOR_X; INTO @nome;
...
CLOSE CURSOR_X;
Modelo pratico
CREATE PROCEDURE `looping_cursor` ()
BENGIN
DECLARE limite_cursor INT DEFAULT 0;
DECLARE vNome VARCHAR(45);
DECLARE c CURSOR FOR SELECT COLUNA FROM tabela LIMIT 3;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET limite_cursor= 1;
OPEN c;
WHILE limite_cursor = 0
DO
FETCH c INTO vNome;
SELECT vNome;
END WHILE;
CLOSE c;
Retornando mais de um campo e concatenando resposta.
Modelo pratico
CREATE PROCEDURE `retorno_cursor` ()
BENGIN
DECLARE limite_cursor INT DEFAULT 0;
DECLARE vNome, vPlataforma VARCHAR(45);
DECLARE vNivel, vMemoria TINYINT;
DECLARE c CURSOR FOR SELECT COLUNA, COLUNA1, COLUNA2, COLUNA3 FROM tabela;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET limite_cursor= 1;
OPEN c;
WHILE limite_cursor = 0
DO
FETCH c INTO vNome, vPlataforma, vNivel, vMemoria;
IF limite_cursor = 0 then
SELECT concat(vNome, '-', vPlataforma, 'NV: ', vNivel, 'Memoria: ', vMemoria);
END IF;
END WHILE;
CLOSE c;
END $$
Funções
Função é uma serie de comandos bem estruturado que diferente de rotina no final me retorna um valor. A usabilidade das funções são como as nativas do MySQL (avg, concat, sum) é possível criar uma aplicabilidade infinita.
Normalmente as instalações MySQL não permitem a criação de funções, para isso é necessário executar a linha de comando SET GLOBAL log_bin_trust_function_creators = 1;
Estrutura básica;
CREATE FUNCTION `name_function`(parameters)
RETURNS datatype;
BEGIN
DECLARE declaration_statement;
executable_statement;
RETURN statement;
END;
Diferente de uma procedure a function é chamada por SELECT
.
Modelo pratico
...
CREATE FUNCTION `f_memoria`(vMemoria tinyint)
RETURNS varchar(27) CHARSET utf8
BEGIN
declare vRetorno varchar(27) default "";
CASE vMemoria
when 1 then set vRetorno = 'Boa';
when 2 then set vRetorno = 'Moderada';
when 3 then set vRetorno = 'Decaindo';
when 4 then set vRetorno = 'Esquecimento';
when 5 then set vRetorno = 'Vaga Lembrança';
else set vRetorno = 'Ainda não começou';
end case;
RETURN vRetorno;
END $$
utilizando
SELECT COLUNA, f_memoria(COLUNA1) FROM tabela;
Gerando números aleatórios.
CREATE FUNCION `num_aleatorio`(min int, max int)
RETURNS INT
BEGIN
DECLARE vRetorno INT;
SELECT FLOOR((RAND() * (max - min + 1))+ min) INTO vRetorno;
RETURN vRetorno;
END
Triggers
É um gatilho ou um escutador de processos DML. Estrutura básica;
CREATE TRIGGER nome TIME EVENT
ON tabela
FOR EACH ROW
declarações
O mesmo pode ser separado nos tempos BEFORE, AFTER
.
E nas operações DML INSERT, UPDATE, DELETE
.
Modelo pratico
CREATE TRIGGER tr_nome BEFORE INSERT
ON tabela
FOR EACH ROW
SET NEW.coluna3 = (NEW.coluna1 * x);
Disparado
INSERT INTO tabela (coluna, coluna1)
VALUES ('exemplo', 9);