导致INSERT失败的TRIGGER? 可能?

在清理这个答案的过程中,我学习了一些关于TRIGGER和MySQL的存储过程,但是惊讶的是,尽pipeBEFORE INSERTBEFORE UPDATE触发器可以修改数据,但看起来不会导致插入/更新失败)。 在这种特殊情况下,我可以通过操纵数据来达到这个目的,从而导致主键复制,在这种情况下,这是有意义的,但是在一般意义上并不一定有意义。

这种function在MySQL中可能吗? 在其他任何RDBMS(我的经验仅限于MySQL)。 也许是一个THROW EXCEPTION风格的语法?

从这个博客文章

MySQL触发器:如何用触发器中止INSERT,UPDATE或DELETE? 在EfNet的#mysql上有人问:

如果我的业务规则失败,如何使触发器中止操作?

在MySQL 5.0和5.1中,你需要使用一些技巧来使触发失败,并提供一个有意义的错误信息。 MySQL存储过程常见问题解答说明了这个error handling:

SP 11. SP是否有“提出”声明来“引发应用程序错误”? 对不起,目前没有。 SQL标准SIGNAL和RESIGNAL语句在TODO上。

也许MySQL 5.2将包括SIGNAL语句,这将使得这个黑客直接从MySQL存储过程编程中被淘汰。 什么是黑客? 您将强制MySQL尝试使用不存在的列。 丑陋? 是。 它工作吗? 当然。

 CREATE TRIGGER mytabletriggerexample BEFORE INSERT FOR EACH ROW BEGIN IF(NEW.important_value) < (fancy * dancy * calculation) THEN DECLARE dummy INT; SELECT Your meaningful error message goes here INTO dummy FROM mytable WHERE mytable.id=new.id END IF; END; 

这是我做到的。 注意SET NEW='some error'; 。 MySQL会告诉你“variablesnew”不能设置为'Error'的值错误:不能删除这个项目,这个项目的销售表中有logging。

你可以将它陷入你的代码,然后显示出错:)

 DELIMITER $$ DROP TRIGGER IF EXISTS before_tblinventoryexceptionreasons_delete $$ CREATE TRIGGER before_tblinventoryexceptionreasons_delete BEFORE DELETE ON tblinventoryexceptionreasons FOR EACH ROW BEGIN IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblinventoryexceptionreasons = old.idtblinventoryexceptionreasons) > 0 THEN SET NEW='Error: Cannot delete this item. There are records in the inventory exception reasons table with this item.'; END IF; END$$ DELIMITER ; DELIMITER $$ DROP TRIGGER IF EXISTS before_storesalesconfig_delete $$ CREATE TRIGGER before_storesalesconfig_delete BEFORE DELETE ON tblstoresalesconfig FOR EACH ROW BEGIN IF (SELECT COUNT(*) FROM tblstoresales WHERE tblstoresales.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0 THEN SET NEW='Error: Cannot delete this item. There are records in the sales table with this item.'; END IF; IF (SELECT COUNT(*) FROM tblinventory WHERE tblinventory.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0 THEN SET NEW='Error: Cannot delete this item. There are records in the inventory table with this item.'; END IF; IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0 THEN SET NEW='Error: Cannot delete this item. There are records in the inventory exceptions table with this item.'; END IF; IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0 THEN SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.'; END IF; END$$ DELIMITER ; DELIMITER $$ DROP TRIGGER IF EXISTS before_tblinvoice_delete $$ CREATE TRIGGER before_tblinvoice_delete BEFORE DELETE ON tblinvoice FOR EACH ROW BEGIN IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblinvoice = old.idtblinvoice) > 0 THEN SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.'; END IF; END$$ DELIMITER ; 

因为当我在MySQL触发器中searcherror handling时,这篇文章出现在顶端,我想我会分享一些知识。

如果出现错误,您可以强制MySQL使用SIGNAL ,但是如果您没有将其指定为SQLEXCEPTION类,则不会发生任何事情,因为不是所有的SQLSTATE都被认为是不好的,即使这样,您也必须如果您有嵌套的BEGIN / END块,请确保RESIGNAL 。

另外,也许更简单,在你的触发器中,声明一个退出处理程序并重新发出exception。

 CREATE TRIGGER `my_table_AINS` AFTER INSERT ON `my_table` FOR EACH ROW BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION RESIGNAL; DECLARE EXIT HANDLER FOR SQLWARNING RESIGNAL; DECLARE EXIT HANDLER FOR NOT FOUND RESIGNAL; -- Do the work of the trigger. END 

如果在你的身体出现错误,它将被抛回到顶部,并退出一个错误。 这也可以用于存储过程和什么。

这适用于任何版本5.5+。

这将通过引发exception来中止INSERT(来自http://www.experts-exchange.com/Database/MySQL/Q_23788965.html

 DROP PROCEDURE IF EXISTS `MyRaiseError`$$ CREATE PROCEDURE `MyRaiseError`(msg VARCHAR(62)) BEGIN DECLARE Tmsg VARCHAR(80); SET Tmsg = msg; IF (CHAR_LENGTH(TRIM(Tmsg)) = 0 OR Tmsg IS NULL) THEN SET Tmsg = 'ERROR GENERADO'; END IF; SET Tmsg = CONCAT('@@MyError', Tmsg, '@@MyError'); SET @MyError = CONCAT('INSERT INTO', Tmsg); PREPARE stmt FROM @MyError; EXECUTE stmt; DEALLOCATE PREPARE stmt; END$$ 

用法:

 call MyRaiseError('Here error message!'); 

不能在触发器中工作(在存储函数或触发器中不允许使用dynamicSQL)

我用一个很肮脏的解决scheme:

If NEW.test=1 then CALL TEST_CANNOT_BE_SET_TO_1; end if;

当test = 1时,Mysql抛出以下exception:

PROCEDUREpipe理.TEST_CANNOT_BE_SET_TO_1不存在

不复杂但快速和有用。

在MS SQL中,您可以使用适当的语法使其工作:

 IF UPDATE(column_name) BEGIN RAISEERROR ROLLBACK TRAN RETURN END 

http://msdn.microsoft.com/en-us/magazine/cc164047.aspx