Mysql 温故知新系列「触发器详解」

说白了,MySQL触发器就像是数据库里的自动小助手,它在特定时刻自动帮我们完成一些操作。
其实很简单,触发器的作用主要在于数据校验、备份和审计跟踪。

先说最重要的,数据校验,比如去年我们跑的那个项目,我们就用触发器确保了每个用户输入的年龄都必须大于1 8 岁。
另外一点,触发器还能用来做数据备份,比如我们大概3 000量级的数据,在删除前自动备份到另一个表中。

我一开始也以为触发器只能用来在数据插入或更新时起作用,后来发现不对,它还能在删除数据时触发。
等等,还有个事,创建触发器时要注意语法,特别是DELIMITER的更改,不然多语句触发器就只会执行第一条语句。

创建触发器的时候,有几个关键点要记住。
首先,触发器只能在原始表上创建,不能在临时表或视图上。
另外,触发器必须绑定到当前数据库的表,跨数据库创建会导致错误。
还有个细节挺关键的,如果触发器逻辑包含多条SQL语句,需要使用BEGIN...END块,并临时更改语句分隔符。

我觉得值得试试的一个例子是,创建一个触发器在删除数据前将其备份到备份表。
比如这样的代码:
sql DELIMITER // CREATE TRIGGER backup_before_delete BEFORE DELETE ON your_table FOR EACH ROW BEGIN INSERT INTO backup_table(id, name, deleted_at) VALUES(OLD.id, OLD.name, NOW()); END // DELIMITER ;
这个触发器会在每次删除your_table中的记录前,自动将该记录插入到backup_table中,并记录删除时间。
说实话挺坑的,如果忘了更改DELIMITER,多语句触发器就只会执行第一条语句。

所以,创建触发器时,要注意这些细节,确保它按预期工作。
这个点很多人没注意,但我觉得挺重要的。

MySQL创建有多个执行语句的触发器

哎,这事儿吧,我当年搞数据库的时候也踩过坑。
你说的这个触发器,我给你讲讲我碰到的情况。

记得有回我在公司,用MySQL。
那会儿我们表挺多的,有个department表,专门存部门信息的。
然后有个trigger_time表,就是存触发时间点的。

当时有个需求,删除department表里的数据时,得自动在trigger_time表里记下来时间。
一开始我直接写触发器,结果写完发现,这触发器创建不了。
为啥?因为MySQL默认的分号是语句结束符,我触发器里写了两句INSERT,它自动分号分开了,触发器就创建失败了。

我这脑子一热,网上搜了搜,找到个办法,用DELIMITER。
当时我就是在Linux服务器上敲命令行的,黑乎乎的终端窗口里,我敲了DELIMITER &&,然后写触发器,写两句INSERT,最后用&&结束。
创建完,又敲DELIMITER ;,恢复成默认的分号。
这样就没问题了。

你那个例子,DELIMITER &&,然后写两句INSERT,最后用&&结束,再用DELIMITER ;恢复,这个思路是对的。
我当时就是用类似的方法解决的。
创建成功后,你删department表里的数据,trigger_time表里确实会自动多两条记录。
我这儿也是这么验证的。

哦对了,你那个department表和trigger_time表得先建好,数据也得有,不然删的时候没数据,触发器就啥也不干。
我当年就是先建表,然后插点数据进去,再试的。
一步一步来,没问题的。

mysql 触发器 if语句用法

说白了,MySQL的触发器里使用if语句来控制流程,其实很简单。
先说最重要的,你提到的动态SQL执行方式是错误的,触发器内部不能直接执行像你那样返回结果集的SELECT语句。
另外一点,触发器里也不能有返回值,所以你的目的是中断更新操作。

我一开始以为可以直接在触发器里写一个IF语句来检查条件,然后决定是否继续执行更新。
后来发现不对,MySQL触发器里的IF语句是用来判断后续语句是否应该执行的,而不是用来执行其他SQL语句的。
还有个细节挺关键的,触发器里的IF语句需要配合CASE语句或者使用NEW关键字来引用即将更新的行。

所以,如果你想中断更新操作,可以在触发器的CASE语句中使用IF语句来检查条件。
比如:
sql DELIMITER $$
CREATE TRIGGER before_update_trigger BEFORE UPDATE ON your_table FOR EACH ROW BEGIN IF (NEW.column_name = 'some_value') THEN SIGNAL SQLSTATE '4 5 000' SET MESSAGE_TEXT = 'Cannot update this row'; END IF; END$$
DELIMITER ;
这里,如果column_name列的值等于some_value,触发器会抛出一个错误,从而中断更新操作。
说实话挺坑的,因为MySQL没有直接的方式来在触发器中返回一个布尔值来控制流程。

我觉得值得试试的是,在触发器中使用SIGNAL语句来抛出错误,这是一种比较标准的做法。
等等,还有个事,如果你只是想简单地检查条件并决定是否继续执行,也可以考虑使用BEFORE UPDATE触发器中的CASE语句来替代IF语句。