MySQL Server里面也就是对某一个表的一定的操作,触发某种条(Insert,Update,Delete 等),从而自动执行的一段程序。从这种意义上讲触发器是一个特殊的存储过程。
#语法
CREATE TRIGGER <触发器名称> --触发器必须有名字,最多64个字符,可能后面会附有分隔符.它和MySQL中其他对象的命名方式基本相象.
{ BEFORE | AFTER } --触发器有执行的时间设置:可以设置为事件发生前或后。
{ INSERT | UPDATE | DELETE } --同样也能设定触发的事件:它们可以在执行insert、update或delete的过程中触发。
ON <表名称> --触发器是属于某一个表的:当在这个表上执行插入、 更新或删除操作的时候就导致触发器的激活. 我们不能给同一张表的同一个事件安排两个触发器。
FOR EACH ROW --触发器的执行间隔:FOR EACH ROW子句通知触发器 每隔一行执行一次动作,而不是对整个表执行一次。
<触发器SQL语句> --触发器包含所要触发的SQL语句:这里的语句可以是任何合法的语句, 包括复合语句,但是这里的语句受的限制和函数的一样。
作用:
监视某表的变化,当发生某种变化时,触发某个操作,
能监视:增,删,改
触发操作:增,删,改
触发器应用场景:
1.当向一张表中添加或删除记录时,需要在相关表中进行同步操作。
比如,当一个订单产生时,订单所购的商品的库存量相应减少。
2.当表上某列数据的值与其他表中的数据有联系时。
比如,当某客户进行欠款消费,
可以在生成订单时通过设计触发器判断该客户的累计欠款是否超出了最大限度。
3.当需要对某张表进行跟踪时。
比如,当有新订单产生时,需要及时通知相关人员进行处理,
此时可以在订单表上设计添加触发器加以实现
BEGIN…END语句中也可以定义变量,但是只能在BEGIN…END内部使用:
DECLARE var_name var_type [DEFAULT value] #定义变量,可指定默认值
SET var_name = value #给变量赋值
需求:有两张表,一张订单表,一张商品表,。
– 创建表
create table goods(
id int primary key auto_increment,
name varchar(20) not null,
price decimal(10,2) default 1,
inv int comment ‘库存数量’
) charset utf8;
insert into goods values(null,‘荣耀3c’,999,100),
(null,‘魅族3c’,1299,50),
(null,‘iphone6s’,5999,200),
(null,‘荣耀6’,1999,250),
(null,‘iphonese’,2999,300);
create table orders(
id int primary key auto_increment,
o_id int not null comment ‘商品id’,
o_number int comment ‘商品数量’
) charset utf8
1创建insert触发器:1:每生成一个订单,意味着商品的库存要减少
delimiter − − 临 时 修 改 语 句 结 束 符 c r e a t e t r i g g e r t 1 a f t e r i n s e r t o n o r d e r s f o r e a c h r o w b e g i n − − 触 发 器 内 容 开 始 u p d a t e g o o d s s e t i n v = i n v − n e w . o n u m b e r w h e r e i d = n e w . o i d ; e n d -- 临时修改语句结束符 create trigger t1 after insert on orders for each row begin -- 触发器内容开始 update goods set inv = inv - new.o_number where id = new.o_id; end −−临时修改语句结束符createtriggert1afterinsertonordersforeachrowbegin−−触发器内容开始updategoodssetinv=inv−new.onumberwhereid=new.oid;end – 结束触发器
delimiter ; – 修改临时语句结束符
触发:
触发器保存表:所有的触发器都会保存在一张表中,information_schema.triggers
select * from information_schema.triggers\G
列出触发器:SHOW TRIGGERS like ‘%ttlsa%’;
SHOW TRIGGERS from database_name; #列出数据库的触发器
SHOW CREATE TRIGGER trigger_name; #查看创建触发器
select * from information_schema.triggers #查看指定触发器
-> where trigger_name=‘upd_check’\G;
删除触发器:
drop trigger after_order;
2:每修改一个订单,意味着商品的库存要改变
修改订单数量(仅限改数量)
Delimiter c r e a t e t r i g g e r t 2 b e f o r e u p d a t e o n o r d e r s f o r e a c h r o w b e g i n u p d a t e g o o d s s e t i n v = i n v + o l d . o n u m b e r − n e w . o n u m b e r w h e r e i d = n e w . o i d ; e n d create trigger t2 before update on orders for each row begin update goods set inv = inv +old.o_number - new.o_number where id= new.o_id; end createtriggert2beforeupdateonordersforeachrowbeginupdategoodssetinv=inv+old.onumber−new.onumberwhereid=new.oid;end
Delimiter ;
触发:update orders set o_number=0 where id=4;
思考:1:before和after的区别
2:能否在购买量>库存量的情况下,much 自动改为num?
原因:insert 之后,new行已经插入到表中,成为事实,new改不了了。
3:创建delete触发器:每删除一个订单,意味着商品的库存要改变;
Delimiter c r e a t e t r i g g e r t 3 b e f o r e d e l e t e o n o r d e r s f o r e a c h r o w b e g i n u p d a t e g o o d s s e t i n v = i n v + o l d . o n u m b e r w h e r e i d = o l d . o i d ; e n d create trigger t3 before delete on orders for each row begin update goods set inv=inv+old.o_number where id=old.o_id; end createtriggert3beforedeleteonordersforeachrowbeginupdategoodssetinv=inv+old.onumberwhereid=old.oid;end
Delimiter ;
触发:delete from orders where id=3;
4:创建insert触发器,每新增一个订单商品数量大于库存数量,意味着要改变订单的数量商品的库存
Delimiter c r e a t e t r i g g e r t 4 b e f o r e i n s e r t o n o r d e r s f o r e a c h r o w b e g i n D E C L A R E r n u m i n t ( 40 ) ; s e l e c t i n v i n t o r n u m f r o m g o o d s w h e r e i d = n e w . o i d ; i f n e w . o n u m b e r > r n u m t h e n s e t n e w . o n u m b e r = r n u m ; e n d i f ; u p d a t e g o o d s s e t i n v = i n v − n e w . o n u m b e r w h e r e i d = n e w . o i d ; e n d create trigger t4 before insert on orders for each row begin DECLARE rnum int(40); select inv into rnum from goods where id=new.o_id; if new.o_number > rnum then set new. o_number =rnum; end if; update goods set inv=inv - new.o_number where id=new.o_id; end createtriggert4beforeinsertonordersforeachrowbeginDECLARErnumint(40);selectinvintornumfromgoodswhereid=new.oid;ifnew.onumber>rnumthensetnew.onumber=rnum;endif;updategoodssetinv=inv−new.onumberwhereid=new.oid;end
Delimiter ;
触发:
insert into orders values(null,5,400);
for each row作用:
1:oracle 中触发器分语句级触发器和行级触发器;
NEW与OLD详解
• 在触发器的SQL语句中,可以关联表中的任何列,通过使用OLD与NEW列名来标志,如OLD.col_name,NEW.col_name。OLD.col_name关联现有的行的一列的被更新或者删除之前的值。New.col_name关联一个新行的插入或者更新现有的行的一列的值。
• ①对于INSERT语句,只有NEW是合法的。否则会报错:ERROR 1363 (HY000): There is no OLD row in on INSERT trigger
• ②对于DELETE语句,只有OLD是合法的。否则会报错:ERROR 1363 (HY000): There is no NEW row in on DELETE trigger
• ③ 对于UPDATE语句,NEW和OLD可以同时使用。
另外,OLD是只读的,而NEW则可以在触发器中使用 SET 赋值,这样不会再次触发触发器,造成循环调用(如每插入一个学生前,都在其学号前加“2013”)。
例3:mysql> CREATE TRIGGER upd_check BEFORE UPDATE ON account
-> FOR EACH ROW
-> BEGIN
-> IF NEW.amount < 0 THEN
-> SET NEW.amount = 0;
-> ELSEIF NEW.amount > 100 THEN
-> SET NEW.amount = 100;
-> END IF;
-> END$$