5. 触发器实战(教学实例库)
第一部分:入门级实操:INSERT类型触发器
例 1:插入学生时,自动补全「班级」为「默认班」
需求:插入学生时如果没填班级,触发器自动填「默认班」
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER tri_stu_insert_fill_class
BEFORE INSERT ON student FOR EACH ROW
BEGIN
-- 没填班级就自动赋值为「默认班」
IF NEW.class IS NULL THEN
SET NEW.class = '默认班';
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 插入学生时不填班级
INSERT INTO student(Sno, Sname, Ssex) VALUES ('999', '新手测试', '男');
-- 查看结果:class字段已自动填充为「默认班」
SELECT Sno, Sname, class FROM student WHERE Sno='999';例 2:插入成绩时,强制分数不能小于 0
需求:插入成绩时如果填了负数,自动改成 0
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER tri_sc_insert_check_score
BEFORE INSERT ON sc FOR EACH ROW
BEGIN
-- 分数<0就强制设为0
IF NEW.score < 0 THEN
SET NEW.score = 0;
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 插入负数分数(会被自动改成0)
INSERT INTO sc(Sno, Cno, score) VALUES ('999', '01', -10);
-- 查看结果:score=0
SELECT Sno, Cno, score FROM sc WHERE Sno='999' AND Cno='01';例 3:插入教师时,自动填充「入职时间」为当前日期
需求:插入教师时不填入职日期,触发器自动填今天(新手易理解的时间赋值)
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER tri_teacher_insert_fill_date
BEFORE INSERT ON teacher FOR EACH ROW
BEGIN
-- 入职日期为空就填当前时间
IF NEW.entrydate IS NULL THEN
SET NEW.entrydate = CURDATE();
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 插入教师时不填入职日期
INSERT INTO teacher(Tno, Tname) VALUES ('99', '新手老师');
-- 查看结果:entrydate=今天的日期
SELECT Tno, Tname, entrydate FROM teacher WHERE Tno='99';例 4:插入课程时,课程号自动加前缀「KC-」
需求:插入课程时,自动给课程号加固定前缀(极简字符串拼接)
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER tri_course_insert_add_prefix
BEFORE INSERT ON course FOR EACH ROW
BEGIN
-- 课程号拼接前缀「KC-」
SET NEW.Cno = CONCAT('KC-', NEW.Cno);
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 插入课程号为09的课程
INSERT INTO course(Cno, Cname) VALUES ('09', '新手课程');
-- 查看结果:Cno=KC-09
SELECT Cno, Cname FROM course WHERE Cname='新手课程';例 5:学生性别合法性前置校验
需求:性别只能是「男」或「女」
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_student_before_insert_sex_check
BEFORE INSERT ON student FOR EACH ROW
BEGIN
IF NEW.Ssex NOT IN ('男','女') THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '性别只能填写「男」或「女」,插入失败';
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 合法插入
INSERT INTO student(Sno,Sname,Ssex) VALUES ('021','测试同学','男');
-- 非法插入(会报错)
INSERT INTO student(Sno,Sname,Ssex) VALUES ('022','测试同学2','保密');例 6:插入学生时自动计算年龄
需求:仅填出生日期,自动计算并填充 sage
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_student_before_insert_auto_age
BEFORE INSERT ON student FOR EACH ROW
BEGIN
SET NEW.sage = TIMESTAMPDIFF(YEAR, NEW.Sbirth, CURDATE());
END //
DELIMITER ;查看测试语句(可复制)
sql
INSERT INTO student(Sno,Sname,Sbirth,Ssex) VALUES ('023','张三','2010-05-20','男');
SELECT Sno,Sname,Sbirth,sage FROM student WHERE Sno='023';例 7:新增学生后自动分配必修课程成绩
需求:自动插入语文(01)、数学(02)、英语(03),默认0分
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_student_after_insert_auto_course
AFTER INSERT ON student FOR EACH ROW
BEGIN
INSERT INTO sc(Sno,Cno,score) VALUES
(NEW.Sno,'01',0.0),
(NEW.Sno,'02',0.0),
(NEW.Sno,'03',0.0);
END //
DELIMITER ;查看测试语句(可复制)
sql
INSERT INTO student(Sno,Sname,Sbirth,Ssex) VALUES ('024','李四','2009-08-15','女');
SELECT * FROM sc WHERE Sno='024';例 8:教师入职日期合法性校验
需求:入职日期不能晚于当前日期
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_teacher_before_insert_entrydate_check
BEFORE INSERT ON teacher FOR EACH ROW
BEGIN
IF NEW.entrydate > CURDATE() THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '入职日期不能晚于当前日期,插入失败';
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 合法
INSERT INTO teacher(Tno,Tname,entrydate) VALUES ('05','孙老师','2025-01-01');
-- 非法(报错)
INSERT INTO teacher(Tno,Tname,entrydate) VALUES ('06','周老师','2026-01-01');第二部分:进阶级实操:UPDATE类型触发器
例 9:不允许修改学生姓名,自动提示「"学号:XXX姓名从XXX改成XXX"
需求:修改学生姓名后,触发器抛出提示 "学号:XXX姓名从XXX改成XXX"
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER tri_stu_update_tip_name
AFTER UPDATE ON student FOR EACH ROW
BEGIN
-- 1.定义一个变量msg
# DECLARE msg VARCHAR(100);
-- 2. 先拼接字符串到变量中
# SET msg = CONCAT('学号', OLD.Sno, '姓名从', OLD.Sname, '改成', NEW.Sname);
-- 只有姓名改了才提示
IF OLD.Sname != NEW.Sname THEN
SELECT CONCAT('学号', OLD.Sno, '姓名从', OLD.Sname, '改成', NEW.Sname) AS提示信息;
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 修改999号学生的姓名(执行会报错提示,验证触发器生效)
UPDATE student SET Sname='测试改名' WHERE Sno='999';例 10:修改成绩时,分数超过 100 自动改成 100
需求:修改成绩时如果填了 100 以上的数,自动修正为 100
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER tri_sc_update_fix_score
BEFORE UPDATE ON sc FOR EACH ROW
BEGIN
-- 分数>100就强制设为100
IF NEW.score > 100 THEN
SET NEW.score = 100;
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 把999号学生的成绩改成150(会被自动改成100)
UPDATE sc SET score=150 WHERE Sno='999' AND Cno='01';
-- 查看结果:score=100
SELECT Sno, Cno, score FROM sc WHERE Sno='999' AND Cno='01';第三部分:进阶级实操:DELETE类型触发器
例 11:禁止删除任何课程(固定拦截,无复杂判断)
需求:只要删除课程表数据,就直接拦截(新手易理解的「禁止删除」)
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER tri_course_delete_forbid
BEFORE DELETE ON course FOR EACH ROW
BEGIN
-- 直接抛出错误,禁止删除
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '禁止删除课程表数据!';
END //
DELIMITER ;
-- 【测试语句】
DELETE FROM course WHERE Cno='01';例 12:禁止删除有成绩记录的学生
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_student_before_delete_check
BEFORE DELETE ON student FOR EACH ROW
BEGIN
IF EXISTS (SELECT 1 FROM sc WHERE Sno=OLD.Sno) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '该学生存在成绩记录,禁止删除';
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 删除有成绩的(报错)
DELETE FROM student WHERE Sno='001';
-- 删除无成绩的
DELETE FROM student WHERE Sno='008';例 13:删除学生后自动级联删除成绩记录
【注意】:请先删除上面的实例1触发器,避免冲突 DROP TRIGGER IF EXISTS trigger_student_before_delete_check;
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_student_after_delete_cascade_sc
AFTER DELETE ON student FOR EACH ROW
BEGIN
DELETE FROM sc WHERE Sno=OLD.Sno;
END //
DELIMITER ;查看测试语句(可复制)
sql
DELETE FROM student WHERE Sno='004';
SELECT * FROM sc WHERE Sno='004';例 14:禁止删除有授课记录的教师
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_teacher_before_delete_check
BEFORE DELETE ON teacher FOR EACH ROW
BEGIN
IF EXISTS (SELECT 1 FROM course WHERE Tno=OLD.Tno) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '该教师有授课记录,禁止删除';
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 删除有授课的(报错)
DELETE FROM teacher WHERE Tno='01';
-- 删除无授课的
DELETE FROM teacher WHERE Tno='04';例 15:删除课程自动记录归档日志
第一步:创建日志表
查看参考答案(可复制)
sql
CREATE TABLE IF NOT EXISTS course_delete_log (
id INT AUTO_INCREMENT PRIMARY KEY,
Cno VARCHAR(10) NOT NULL COMMENT '课程编号',
Cname VARCHAR(10) NOT NULL COMMENT '课程名称',
Tno VARCHAR(10) COMMENT '授课教师编号',
delete_time DATETIME NOT NULL DEFAULT NOW() COMMENT '删除时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;第二步:创建触发器
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_course_after_delete_log
AFTER DELETE ON course FOR EACH ROW
BEGIN
INSERT INTO course_delete_log(Cno,Cname,Tno)
VALUES (OLD.Cno, OLD.Cname, OLD.Tno);
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 先清理关联数据
DELETE FROM sc WHERE Cno='04';
-- 删除课程
DELETE FROM course WHERE Cno='04';
-- 查看日志
SELECT * FROM course_delete_log;第四部分:高阶实操:触发器复杂业务场景
例 16:教师排课数量上限校验,
需求:每名老师最多排2门课,多排提示"老师最多只能排2门课"
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_sc_before_insert_course_limit
BEFORE INSERT ON course FOR EACH ROW
BEGIN
DECLARE teacher_count INT DEFAULT 0;
SELECT COUNT(*) INTO teacher_count FROM course WHERE tno=NEW.tno;
IF teacher_count >=2 THEN
SIGNAL SQLSTATE '10001' SET MESSAGE_TEXT = '老师最多只能排2门课';
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 教师01已选2门,插入报错
INSERT INTO course(Sno,Cname,tno) VALUES ('05','Python','01');
-- 教师02未选满,插入成功
INSERT INTO sc(Sno,Cno,score) VALUES ('05','Python','02');例 17:成绩插入时自动计算等级
第一步:给sc表新增等级字段
查看参考答案(可复制)
sql
ALTER TABLE sc ADD COLUMN grade_level VARCHAR(10) COMMENT '成绩等级' AFTER score;第二步:创建INSERT触发器
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_sc_before_insert_auto_grade
BEFORE INSERT ON sc FOR EACH ROW
BEGIN
set new.grade_level=(SELECT grade_level
FROM grades
WHERE NEW.score BETWEEN lowest_sc AND highest_sc);
END //
DELIMITER ;拓展:成绩更新时,自动计算等级
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_sc_before_update_auto_grade
BEFORE UPDATE ON sc FOR EACH ROW
BEGIN
IF OLD.score != NEW.score THEN
set new.grade_level=(SELECT grade_level
FROM grades
WHERE NEW.score BETWEEN lowest_sc AND highest_sc);
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
INSERT INTO sc(Sno,Cno,score) VALUES ('009','02',85.0);
SELECT * FROM sc WHERE Sno='009';
UPDATE sc SET score=95.0 WHERE Sno='009' AND Cno='02';
SELECT * FROM sc WHERE Sno='009' AND Cno='02';例 18:教师编号修改自动级联更新课程表
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_teacher_after_update_tno_cascade
AFTER UPDATE ON teacher FOR EACH ROW
BEGIN
IF OLD.Tno != NEW.Tno THEN
UPDATE course SET Tno=NEW.Tno WHERE Tno=OLD.Tno;
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 先恢复数据(如果之前删了)
INSERT INTO teacher(Tno,Tname,entrydate) VALUES ('01','张老师','2017-08-30');
-- 修改编号
UPDATE teacher SET Tno='10' WHERE Tno='01';
-- 查看课程表
SELECT * FROM course WHERE Cname='数学';例 19:课程选课人数上限强校验
需求:每门课最多10人选
查看参考答案(可复制)
sql
DELIMITER //
CREATE TRIGGER trigger_sc_before_insert_course_stu_limit
BEFORE INSERT ON sc FOR EACH ROW
BEGIN
DECLARE stu_count INT DEFAULT 0;
SELECT COUNT(*) INTO stu_count FROM sc WHERE Cno=NEW.Cno;
IF stu_count >=10 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '该课程选课人数已达上限10人,选课失败';
END IF;
END //
DELIMITER ;查看测试语句(可复制)
sql
-- 尝试给语文(01)插入第11人(会报错)
INSERT INTO sc(Sno,Cno,score) VALUES ('012','01',85.0);