As vezes acho que esse MySQL não pode estar sendo usado para valer por empresas reais, domundo real, etc... ou eu que sou paranôico e gosto de fazer uma grande parte da lógica dosmeus sistemas no banco de dados dividindo essaresponsabilidade 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 seriaum trabalho insano, onde TODO o controle datransação estaria na minha mão, e eu nem sei seisso é 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 issotudo.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: 0mysql> ALTER TABLE CONTATO ADD INDEX (CODCONTATO);Saída no console: Query OK, 0 rows affected (0.01 sec)Records: 0 Duplicates: 0 Warnings: 0mysql> 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: 0mysql> 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: 0mysql> 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: 0mysql> 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.