在MySQL触发器中抛出一个错误

如果我before the updatebefore the update有一个trigger ,我怎样才能抛出一个错误,阻止该表上的更新?

这是一个可能工作的黑客 。 这不是干净的,但它看起来可能会工作:

基本上,你只是尝试更新不存在的列。

从MySQL 5.5开始,您可以使用SIGNAL语法来引发exception :

 signal sqlstate '45000' set message_text = 'My Error Message'; 

状态45000是表示“未处理的用户定义的exception”的通用状态。


这是一个更完整的方法的例子:

 delimiter // use test// create table trigger_test ( id int not null )// drop trigger if exists trg_trigger_test_ins // create trigger trg_trigger_test_ins before insert on trigger_test for each row begin declare msg varchar(128); if new.id < 0 then set msg = concat('MyTriggerError: Trying to insert a negative value in trigger_test: ', cast(new.id as char)); signal sqlstate '45000' set message_text = msg; end if; end // delimiter ; -- run the following as seperate statements: insert into trigger_test values (1), (-1), (2); -- everything fails as one row is bad select * from trigger_test; insert into trigger_test values (1); -- succeeds as expected insert into trigger_test values (-1); -- fails as expected select * from trigger_test; 

不幸的是,@RuiDC提供的答案在5.5之前的MySQL版本中不起作用,因为没有存储过程的SIGNAL的实现。

我find的解决scheme是模拟信号引发table_name doesn't exist错误,将自定义的错误消息推送到table_name

黑客可以使用触发器或使用存储过程来实现。 我将在下面的@RuiDC使用的示例中描述这两个选项。

使用触发器

 DELIMITER $$ -- before inserting new id DROP TRIGGER IF EXISTS before_insert_id$$ CREATE TRIGGER before_insert_id BEFORE INSERT ON test FOR EACH ROW BEGIN -- condition to check IF NEW.id < 0 THEN -- hack to solve absence of SIGNAL/prepared statements in triggers UPDATE `Error: invalid_id_test` SET x=1; END IF; END$$ DELIMITER ; 

使用存储过程

存储过程允许您使用dynamicsql,这使得可以在一个过程中封装错误生成function。 对应的是我们应该控制应用程序的插入/更新方法,所以他们只使用我们的存储过程(不直接授予INSERT / UPDATE权限)。

 DELIMITER $$ -- my_signal procedure CREATE PROCEDURE `my_signal`(in_errortext VARCHAR(255)) BEGIN SET @sql=CONCAT('UPDATE `', in_errortext, '` SET x=1'); PREPARE my_signal_stmt FROM @sql; EXECUTE my_signal_stmt; DEALLOCATE PREPARE my_signal_stmt; END$$ CREATE PROCEDURE insert_test(p_id INT) BEGIN IF NEW.id < 0 THEN CALL my_signal('Error: invalid_id_test; Id must be a positive integer'); ELSE INSERT INTO test (id) VALUES (p_id); END IF; END$$ DELIMITER ; 

以下过程(在mysql5上)是一种抛出自定义错误的方法,并同时logging它们:

 create table mysql_error_generator(error_field varchar(64) unique) engine INNODB; DELIMITER $$ CREATE PROCEDURE throwCustomError(IN errorText VARCHAR(44)) BEGIN DECLARE errorWithDate varchar(64); select concat("[",DATE_FORMAT(now(),"%Y%m%d %T"),"] ", errorText) into errorWithDate; INSERT IGNORE INTO mysql_error_generator(error_field) VALUES (errorWithDate); INSERT INTO mysql_error_generator(error_field) VALUES (errorWithDate); END; $$ DELIMITER ; call throwCustomError("Custom error message with log support."); 

另一个(黑客)方法(如果你不是在5.5+出于某种原因),你可以使用:

如果您有必填字段,则在触发器中将必填字段设置为无效值(如NULL)。 这将同时适用于INSERT和UPDATE。 请注意,如果NULL是所需字段的有效值(出于某种疯狂的原因),那么这种方法将不起作用。

 BEGIN -- Force one of the following to be assigned otherwise set required field to null which will throw an error IF (NEW.`nullable_field_1` IS NULL AND NEW.`nullable_field_2` IS NULL) THEN SET NEW.`required_id_field`=NULL; END IF; END 

如果你在5.5+以上,那么你可以使用其他答案中描述的信号状态:

 BEGIN -- Force one of the following to be assigned otherwise use signal sqlstate to throw a unique error IF (NEW.`nullable_field_1` IS NULL AND NEW.`nullable_field_2` IS NULL) THEN SIGNAL SQLSTATE '45000' set message_text='A unique identifier for nullable_field_1 OR nullable_field_2 is required!'; END IF; END 
 CREATE TRIGGER sample_trigger_msg BEFORE INSERT FOR EACH ROW BEGIN IF(NEW.important_value) < (1*2) THEN DECLARE dummy INT; SELECT Enter your Message Here!!! INTO dummy FROM mytable WHERE mytable.id=new.id END IF; END;