sendo usado para valer por empresas reais, do
mundo real, etc... ou eu que sou paranôico e
gosto de fazer uma grande parte da lógica dos
meus sistemas no banco de dados dividindo essa
responsabilidade com a aplicação. Não sei se
isso é certo, bom tema para uma discussão, quem
quizer pode postar aí o que acha. ;)
Bom estava eu aqui feliz da vida quando me de-
parei com um fato lamentável... no MySQL não
tenho como "matar" um gatilho, procedimento,
etc... Não há uma instrução semelhante a
RAISE_APPLICATION_ERROR do Oracle.
Caramba, e agora? Criar um procedimento que
trate os erros da aplicação? Insano! Não vou
escrever isso, isso tem que ser feito pelos de-
senvolvedores do SGBD e não por mim (po que má
vontade a minha :P)!
Mas a idéia até que por hora, apenas por hora,
soa como uma gambiarra (um bacalhau como eu
prefiro dizer) razoável. Mas mesmo assim seria
um trabalho insano, onde TODO o controle da
transação estaria na minha mão, e eu nem sei se
isso é possível!
Seria mais ou menos isso:
CREATE PROCEDURE x (INT parametro1 INT, OUT
resultado INT, OUT sqlError)
BEGIN
-- Digamos que eu tenha um select aqui dentro
-- e que o mesmo não possa vir 0 ou nulo em
-- um determinado campo.
-- Eu percorreria meu cursor e a cada linha
-- testaria se há valor no campo, se não ti-
-- ver eu setor meu sqlError com uma mensagem
-- de erro qualquer e pararia o loop.
-- Na aplicação eu teria que controlar se ele
-- é nulo, se for faz alguma coisa ou até
-- mesmo manda o banco dar commit\rollback no
-- procedimento e então poderia chamar uma
-- p_erros(IN mensagem, OUT erro); Que retor-
-- naria uma mensagem baseada em um código,
--etc...
END;
Fiquei cansado só de pensar em implementar isso
tudo.
Fica aqui um exemplo e como trabalhar com pro-
cedimentos e cursores.
Usando a base de dados TESTE que criamos:
mysql> DROP TABLE IF EXISTS Recado;
Saída no console: Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS Contato;
Saída no console: Query OK, 0 rows affected (0.00 sec)
mysql> DROP PROCEDURE IF EXISTS
P_RECADOSPORCONTATO;
Saída no console: Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> CREATE TABLE CONTATO(
CODCONTATO INT NOT NULL,
NOMECONTATO VARCHAR(100) NOT NULL
) ENGINE = INNODB;
Saída no console: Query OK, 0 rows affected (0.00 sec)
mysql> ALTER TABLE CONTATO ADD PRIMARY KEY (CODCONTATO);
Saída no console: Query OK, 0 rows affected
Records: 0 Duplicates: 0 Warnings: 0
mysql> ALTER TABLE CONTATO ADD INDEX (CODCONTATO);
Saída no console: Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> DELIMITER //
mysql> CREATE TRIGGER BIF_CONTATO BEFORE INSERT ON CONTATO
FOR EACH ROW
BEGIN
DECLARE novoCodigo INT;
SELECT IFNULL(MAX(CodContato), 0) + 1
INTO novoCodigo
FROM Contato;
SET NEW.CodContato = novoCodigo;
END;
//
Saída no console: Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TRIGGER BUF_CONTATO BEFORE UPDATE ON CONTATO
FOR EACH ROW
BEGIN
SET NEW.CodContato = OLD.CodContato;
END;
//
Saída no console: Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO Contato(CODCONTATO, NOMECONTATO) VALUES(0, 'Joao');
Saída no console: Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO Contato(CODCONTATO, NOMECONTATO) VALUES(0, 'Maria');
Saída no console: Query OK, 1 row affected (0.00 sec)
mysql> CREATE TABLE RECADO(
CODCONTATO INT NOT NULL,
RECADO VARCHAR(500) NOT NULL,
CODREMETENTE INT NOT NULL
) ENGINE = INNODB;
Saída no console: Query OK, 0 rows affected (0.00 sec)
mysql> ALTER TABLE RECADO ADD INDEX (CODCONTATO);
Saída no console: Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> ALTER TABLE RECADO ADD FOREIGN KEY (CODCONTATO) REFERENCES CONTATO(CODCONTATO) ON DELETE CASCADE;
Saída no console: Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> ALTER TABLE RECADO ADD FOREIGN KEY (CODREMETENTE) REFERENCES CONTATO(CODCONTATO) ON DELETE CASCADE;
Saída no console: Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> INSERT INTO Recado(CodContato, Recado, CodRemetente) VALUES(2, 'Nao esquece do happy hour hoje!', 1);
Saída no console: Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO Recado(CodContato, Recado, CodRemetente) VALUES(1, 'Ok, irei sem falta.', 2);
Saída no console: Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO Recado(CodContato, Recado, CodRemetente) VALUES(2, 'É lá no buteco do Joaquin.', 1);
Saída no console: Query OK, 1 row affected (0.02 sec)
mysql> DELIMITER //
mysql> CREATE PROCEDURE P_RECADOSPORCONTATO(IN CodContato INT
, OUT total INT)
BEGIN
-- Variável que controla o loop
DECLARE linhaFinal INT DEFAULT 0;
-- Recebe o total de recados do contato
DECLARE qtdRecados INT DEFAULT 0;
DECLARE csRecados CURSOR FOR
SELECT COUNT(*)
FROM Recado re
WHERE re.CodContato = CodContato;
-- O controlador do fluxo
DECLARE CONTINUE HANDLER FOR NOT FOUND SET
linhaFinal = 1;
OPEN csRecados; -- Abre o cursor
-- Começa a varedura nos registros
looping: LOOP
-- Coloca na variável os dados da linha atual
FETCH csRecados INTO qtdRecados;
-- Controla para saber se tem que deixar o loop
IF linhaFinal = 1 THEN
LEAVE looping;
END IF;
SET total = qtdRecados; -- Seta uma variável
-- (neste caso um paâmetro)
-- com o resultado do
-- calculo da linha
END LOOP looping; -- Fecha o loop
END;
//
Saída no console: Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CALL P_RECADOSPORCONTATO(2, @resultado);
Saída no console: Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @resultado;
Saída no console:
+------------+
| @resultado |
+------------+
| 2 |
+------------+
1 row in set (0.00 sec)
Em breve: funções.
Nenhum comentário:
Postar um comentário