MySQL-触发器

目录

第1关:为投资表property实现业务约束规则-根据投资类别分别引用不同表的主码

任务描述

相关知识

触发器

触发器的创建

触发器内的特殊表

编程要求

答案:


第1关:为投资表property实现业务约束规则-根据投资类别分别引用不同表的主码

任务描述

本关任务: 为表property(资产表)编写一个触发器,以实现以下完整性业务规则:

如果pro_type = 1, 则pro_pif_id只能引用finances_product表的p_id;

如果pro_type = 2, 则pro_pif_id只能引用insurance表的i_id;

如果pro_type = 3, 则pro_pif_id只能引用fund表的f_id;

pro_type不接受(1,2,3)以外的值。

各投资品种一经销售,不会再改变; 也不需考虑finances_product,insurance,fund的业务规则(一经销售的理财、保险和基金产品信息会永久保存,不会被删除或修改,即使不再销售该类产品)。

相关知识

为了完成本关任务,你需要掌握: (1) MySQL的流程控制编程(参见存储过程实训); (2) 触发器的基本知识; (3) 触发器的创建; (4) 触发触发器的时机; (5) 触发触发器的事件; (6) 触发器内的特殊表。

触发器

触发器是与某个表绑定的命名存储对象,与存储过程一样,它由一组语句组成,当这个表上发生某个操作(insert,delete,update)时,触发器被触发执行。触发器一般用于实现业务完整性规则。当primary key,foreigh key, check等约束都无法实现某个复杂的业务规则时,可以考虑用触发器来实现。

触发器的创建

创建触发器的语句: CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_body

trigger_nme: 每个触发器有一个唯一的命名

trigger_time: 触发的时机,二选一: BEFORE | AFTER

trigger_event: 触发事件,三选一: INSERT | UPDATE | DELETE

tbl_name: 与触发器绑定的表

trigger_body: 触发器程序体,可由变量定义、赋值,流程控制,SQL语句等组成。但触发器体内不能使用create,alter,drop等DDL语句,也不能使用start transaction, commit,rollback等事务相关语句。

与创建存储过程、函数一样,创建触发器时也要用delimiter语句重新指定触发器定义语句的界符(触发器内语句的分隔符仍为分号),在触发器定义之后,再把界符更改回去。

before与after触发器的区别:

before触发器在试图激活触发器的那条语句(insert|delete|update)之前执行。

after触发器仅在before触发器(如果有的话)和试图激活触发器的那条语句都成功执行后才执行。

before触发器或after触发器如果未能成功执行,则激活触发器的语句也不会执行。

触发器内的特殊表

在触发器内可以使用两类特殊表:

old表和new表.它总是与触发器绑定的表有相同的结构,且只能在触发器内访问。

delete触发器可以访问old表,其内容为被delete掉的数据。

insert触发器可以访问new表,其内容为insert的新数据。

update触发器可以访问old表和new表,old表保存着修改前的数据,new表保存着修改后的内容。

 

编程要求

在右侧代码文件编辑器里补充代码,实现本任务所要求的完整性业务规则。当插入的数据不符合要求时,拒绝数据的插入,并反馈出错信息:

(1) pro_type数据不合法时,显示: type x is illegal! 这里,x系指试图插入的pro_type值。

(2) pro_type = 1,但pro_pif_id不是finances_product表中的某个主码值,显示: finances product #x not found! 这里,x系指试图插入的pro_pif_di的值。

(3) pro_type = 2,但pro_pif_id不是insurance表中的某个主码值,显示: insurance #x not found! 这里,x系指试图插入的pro_pif_id的值。

(3) pro_type = 3,但pro_pif_id不是fund表中的某个主码值,显示: fund #x not found! 这里,x系指试图插入的pro_pif_id的值。

提示:

(1) 查阅MySQL的字符串函数,构造出错信息;

(2) 当数据不合法时,用signal sqlstate 语句抛出异常,并设置出错信息: SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg; 其中,通用SQLSTATE '45000'意指用户定义的待处理异常,msg需替换成你想要显示的提示信息(不超过128个字符)。

答案:
USE finance1;

-- 创建触发器
DROP TRIGGER IF EXISTS before_property_inserted;
DELIMITER $$
CREATE TRIGGER before_property_inserted BEFORE INSERT ON property
FOR EACH ROW 
BEGIN
    DECLARE error_msg VARCHAR(128);

    -- 检查 pro_type 的合法性
    IF NEW.pro_type NOT IN (1, 2, 3) THEN
        SET error_msg = CONCAT('type ', NEW.pro_type, ' is illegal!');
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = error_msg;
    END IF;

    -- 检查 pro_pif_id 的引用关系
    IF NEW.pro_type = 1 THEN
        -- 检查 pro_pif_id 是否存在于 finances_product 表中
        IF NOT EXISTS (SELECT * FROM finances_product WHERE p_id = NEW.pro_pif_id) THEN
            SET error_msg = CONCAT('finances product #', NEW.pro_pif_id, ' not found!');
            SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = error_msg;
        END IF;
    ELSEIF NEW.pro_type = 2 THEN
        -- 检查 pro_pif_id 是否存在于 insurance 表中
        IF NOT EXISTS (SELECT * FROM insurance WHERE i_id = NEW.pro_pif_id) THEN
            SET error_msg = CONCAT('insurance #', NEW.pro_pif_id, ' not found!');
            SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = error_msg;
        END IF;
    ELSEIF NEW.pro_type = 3 THEN
        -- 检查 pro_pif_id 是否存在于 fund 表中
        IF NOT EXISTS (SELECT * FROM fund WHERE f_id = NEW.pro_pif_id) THEN
            SET error_msg = CONCAT('fund #', NEW.pro_pif_id, ' not found!');
            SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = error_msg;
        END IF;
    END IF;
END$$
DELIMITER ;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星与星熙.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值