MySQL——触发器(个人笔记整理包含练习题)

定义

触发器与数据表关系密切,主要用于 保护表中的数据。特别是当有多个表具有一定的相互联系的时候,触发器能够让不同的表保持数据的一致性。

应用场景

  1. 增加一条学生记录时,需要检查年龄、性别是否符合范围要求;
  2. 删除一条学生信息时,需要删除其成绩表上的对应记录;
  3. 取消一门课时,同时需要取消选课学生的记录;
  4. 删除或修改数据时,需要备份原来的数据。

创建触发器

Mysq所支持的触发器有三种:INSERT触发器、UPDATE触发器和DELETE触发器

可以使用 CREATE TRIGGER 语句创建触发器,触发器在当前数据库中 必须具有唯一的名称。如果要在某个特定数据库中创建,名称前面应该加上数据库的名称。触发器主体包括在BEGIN…END语句中,可以是一条或多条SQL语句

MySQL——触发器(个人笔记整理包含练习题)_第1张图片

示例:创建一个INSERT触发器,当性别数据错误时,拒绝插入并提示

#创建触发器的触发时间(在每一次row数据插入student之前触发)
CRATE TRIGGER sexcheck BEFORE INSERT ON student FOR EACH ROW   
BEGIN
IF new.sex!='男' and new.sex!='女' then
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '性别错误!';  #错误代码和提示信息
END IF;          #结束if语句
END;

#执行插入触发器生效
insert into student(id,age,sname,sex)
values(7,23,'李四',0);

 示例2:创建一个DELECT/UPDATE触发器,当删除(更新)数据时,先备份该数据到备份表

CREATE TABLE IF NOT EXISTS student_back LIKE student;    #创建备份表
#创建DELETE触发器,在删除student每一条row之前
CREATE TRIGGER deletecheck BEFORE DELETE ON student FOR ROW 
BEGIN 
# 将student_back数据插入select语句的表中
INSERT INTO student_back SELECT * FROM student WHERE id=old.id;
END;            #结束
# 插入数据
INSERT INTO student VALUES(15,'王也',42,'男','武当',DEFAULT);
#删除数据时触发
DElETE FROM student WHERE id=15;

如何查看和删除触发器

# 查看创建触发器的代码
SHOW CREATE TRIGGER sexcheck;

#查看你触发器
SHOW TRIGGERS;

#删除触发器
DROP TRIGGER IF EXISTS sexcheck;

 触发器的作用

➢ 触发器的原理很简单,但在MySQL中引入并使用触发器,可以实现很多实用的效果,并满足一些特定业
务环境的需要。
1. 增强数据库的安全性。例如不允许用户修改数据,不允许用户对某些数据更改超过一定的范围等等。
2. 利用MySQL触发器,可以跟踪用户对数据库的操作。
3. 定义一些复杂规则,可以实现非标准的数据完整性检查和约束。
4. 自动完成任务。利用触发器可以监控数据库中某些异常,例如,当天数据库采集数据为空时报警等

自定义函数

新建一个函数,输入字符串,以‘12X100’样式为例,返回最大的数值。

示例:
CREATE FUNCTION func_x(p VARCHAR(20))
RETURNS INT
BEGIN
DECLARE pout1 INT;
DECLARE pout2 INT;
#将类似的xX统一替换成X
SET p = REPLACE(REPLACE(p,'x','X'),'X','X');
#分别取出两个数值
SET pout1 = SUBSTRING_INDEX(p,'X',1);
SET pout2 = SUBSTRING_INDEX(p,'X',-1);
RETURN GREATEST(pout1,pout2);
END;
#调用函数
SELECT func_x('12x100'), func_x('50X24');

练习题

3.创建触发器:

在客户订购的商品数量超过限购数量时【这里两个变量需要比较】,自动将订购的数量改成限购数量【修改对象表数据】,而后计算出订单总额

create trigger limit_buy before insert on orders for each row
#(这里执行对象是orders,所以orders中的属性都不用定义,可以直接用nwe.属性)
begin
	#(限购数量非orders属性,因此需要定义后再比较)
	declare l_num int;    #定义时,命名最好不要与原属性同名,避免出现运行错误
	declare p double(16,2);
	# 先定义,才有赋值
	set l_num = (select lnum from dishes where did = new.dishesid);#与orders对应数据,才能进行比较
	set p = (select price from dishes where did = new.dishesid);
	if new.num > l_num then
			set new.num = l_num;   # new.属性为插入orders表的数据
			set new.cost = new.num * p;
	end if;
end;
# 插入数据,当条件满足时启动触发器
select * from orders;
select * from dishes;
insert into orders values('111',now(),'2','11','64','1000','27000','3');  #did64,对应限购99

 4.创建触发器

在客户提交订单以后【触发条件,判断表对象】,自动将本次订单的消费金额累加到客户表的消费金额里。并将订单金额累加到卖家表的金额中

create trigger sum_pay after insert on orders for each row
begin
	# 更新表中的内容,因此属性直接用,不用定义再设置值
	update customers set pay = pay + new.cost where cid = new.customerid; #where找到对应数据进行累加
	update sellers set income = income + new.cost where sid = new.sellerid;
end;


# 调用触发器,并检验结果
select * from orders;  #12,6300
select * from sellers;   #10,0
select * from customers; #3,9048
insert into orders values('12',now(),'3','10','64','1000','6300','3');  #did64,对应限购99
select * from sellers where sid='10';
select * from orders where oid='12';
select * from customers where cid='3';
delete from orders where oid='112';

 5.客户取消订单(ostatus=2)【是触发条件,对应的订单表也是触发器对象】,自动从客户的总消费扣除订单金额,同时从卖家的营业额里扣除订单金额
举例:买家下单→买家付款→买家退款

drop trigger if exists t_update;
create trigger t_update after update on orders for each row
begin
	if ostatus ='2' then
	update customers set pay = pay - new.cost where cid = new.customerid;
	update sellers set income = income - new.cost where sid = new.customerid;
	end if;
end;
#调用触发器
update orders set ostatus='2' where oid = '112';

 

6.订单状态自动更新

创建存储过程proc_ostatus,以当前时间标准,检查现有订单,若状态不为2退款并且时间已经超过下单时间15分钟,自动将订单状态修改为0已付款;时间已经超过下单时间1小时,自动将订单状态修改为1已送达;时间超过2小时,自动修改为3已完成。

select TIMESTAMPDIFF(minute,time,now()) from orders where oid ='113';  #timestampdiff(unit,begin,end) 返回begin-end的结果,以unit为时间单位
select * from orders where oid ='113';
drop procedure if exists proc_ostatus;
create procedure proc_ostatus()
begin
	# 大于15分钟,状态修改为0,已付款。在付款前状态为已提交待支付即ostatus=-1
	update orders set ostatus = '0' where timestampdiff(minute,time,now())>15 and ostatus = '-1';
	update orders set ostatus = '1' where timestampdiff(minute,time,now())>60 and ostatus = '0';
	update orders set ostatus = '3' where timestampdiff(hour,time,now())>2 and ostatus = '1';

 7.创建一个时间,每隔3秒执行一次,proc_ostatus来修改订单状态

create event e_proc on schedule every 3 second   #3秒执行一次
start current_timestamp   #现在开始
on completion preserve   #执行完成后不删除事件(完成保存)
do begin
	call proc_ostatus();
end;

INSERT into orders values('115','2022-10-12 15:20:00','2','11','64','1000','27000','-1');
select * from orders;    #查看事件是否执行成功

8.创建一个视图 v_seller_top,查看每天(time)营业金额(sum(cost))前 3 的商家(sellers)

create view v_seller_top as
with a as 
(select date(time) 日期,sellerid,sum(cost) 营业额 from orders group by date(time),sellerid order by 日期,营业额 desc)
select distinct 日期,营业额,sellerid,   #这里将营业额和sellerid去掉
  #因为在a表中已经按照营业额降序排列,因此对每天来说选到的第一个sellerid也为营业额排名第一的商家id
  NTH_VALUE(sellerid,1) over (PARTITION BY 日期) 排名第一的商家id,
	NTH_VALUE(sellerid,2) over (PARTITION BY 日期) 排名第二的商家id,
	NTH_VALUE(sellerid,3) over (PARTITION BY 日期) 排名第三的商家id
  from a;

你可能感兴趣的:(mysql,数据库,sql)