mysql8学习笔记21--游标触发器

cursor游标
• Cursor游标用来声明一个数据集
• 游标的声明必须在变量和条件声明之后,在handler声明之前
• Cursor close语句用来关闭之前打开的游标

• 如果关闭一个未打开的游标,则MySQL会报错
• 如果在存储过程和函数中未使用此语句关闭已经打开的游标,则游标会在声
明的begin…end语句块执行完之后自动关闭
• Cursor declare语句用来声明一个游标和指定游标对应的数据集合,通常数据
集合是一个select语句

• Select_statement代表一个select语句
• Cursor fetch语句用来获取游标指定数据集的下一行数据并将各个字段值赋予
后面的变量
• 数据集中的字段需要和INTO语句中定义的变量一一对应
• 数据集中的数据都fetch完之后,则返回NOT FOUND
• Open cursor语句用来打开一个之前已经声明好的游标

以下是游标例子:

DROP PROCEDURE
IF EXISTS pro_test2;
delimiter $$


CREATE PROCEDURE pro_test2 ()
BEGIN

DECLARE no_more_record INT DEFAULT 0 ;
DECLARE stubirth_year INT ;
DECLARE stu_id INT ;
DECLARE stu_birth VARCHAR (10) ;
DECLARE cursor_test CURSOR FOR SELECT
    stuid,
    stubirth
FROM
    tb_student3 ; /*首先这里对游标进行定义*/
DECLARE CONTINUE HANDLER FOR NOT found
SET no_more_record = 1 ; /*这个是个条件处理,针对NOT FOUND的条件,当没有记录时赋值为1*/
OPEN cursor_test ; /*接着使用OPEN打开游标*/
-- 开始循环
read_loop :
LOOP
    -- 提取游标里的数据,这里只有一个,多个的话也一样;
    FETCH cursor_test INTO stu_id,
    stu_birth ; /*把第一行数据写入变量中,游标也随之指向了记录的第一行*/
    -- 声明结束的时候
SET stubirth_year = CONVERT (
    SUBSTRING_INDEX(stu_birth, '-', 1),
    SIGNED
) ; /*截取年份*/
-- 注意:这里的循环体可以根据自己的需要设定(while,while...do,if...then等等)
IF no_more_record = 1 THEN
    LEAVE read_loop ;
END
IF ; -- 这里做你想做的循环的事件
IF stubirth_year > 1990
AND stubirth_year < 2000 THEN
    UPDATE tb_student3
SET comments = '90后'
WHERE
    stuid = stu_id ;
ELSEIF stubirth_year > 1980
AND stubirth_year < 1990 THEN
    UPDATE tb_student3
SET comments = '80后'
WHERE
    stuid = stu_id ;
ELSEIF stubirth_year > 1970
AND stubirth_year < 1980 THEN
    UPDATE tb_student3
SET comments = '70后'
WHERE
    stuid = stu_id ;
ELSE
    UPDATE tb_student3
SET comments = '有问题'
WHERE
    stuid = stu_id ;
END
IF ;
END
LOOP
    read_loop ; CLOSE cursor_test ; /*用完后记得用CLOSE把资源释放掉*/
    END$$
delimiter ;
 
create trigger语句
• create trigger语句用来创建一个触发器,触发器的作用是当表上
有对应SQL语句发生时,则触发执行
• 触发器创建时需要指定对应的表名tbl_name
CREATE
    [DEFINER = user]
    TRIGGER trigger_name
    trigger_time trigger_event
    ON tbl_name FOR EACH ROW
    [trigger_order]
    trigger_body

trigger_time: { BEFORE | AFTER }

trigger_event: { INSERT | UPDATE | DELETE }

trigger_order: { FOLLOWS | PRECEDES } other_trigger_name
• Definer关键词用来指定trigger的安全环境
• Trigger_time指定触发器的执行时间,BEFORE和AFTER指定触发器在表中的每行数据修改前或者后执行
 
• Trigger_event指定触发该触发器的具体事件
• INSERT当新的一行数据插入表中时触发,比如通过执行insert,loaddata,replace语句插入新数据
• UPDATE当表的一行数据被修改时触发,比如执行update语句时
• DELETE当表的一行数据被删除时触发,比如执行delete,replace语句时
• 当执行insert into … on duplicate key update语句时,当碰到重复行执行update时,则触发update下的触发器
• 从5.7.2版本开始,可以创建具有相同trigger_time和trigger_event的同一个表上的多个触发器,默认情况下按照创建的时间依次执行,通过指定FOLLOWS/PRECEDES改变执行顺序,即FOLLOWS时表示新创建的触发器后执行,PRECEDES则表示新触发器先执行
• Trigger_body表示触发器触发之后要执行的一个或多个语句,在内部可以引用涉及表的字段,OLD.col_name表示行数据被修改或删除之前的字段数据,NEW.col_name表示行数据被插入或修改之后的字段数据
 
 
drop TRIGGER if EXISTS simple_trigger;
delimiter//
create TRIGGER simple_trigger
AFTER UPDATE
on teacher for EACH ROW
BEGIN
insert into h_teacher(tno,new_tname,old_tname,sdate) VALUES(new.tno,new.tname,old.tname,now());

END;
//
delimiter ;
 
mysql> select * from teacher ;
+------+--------+
| tno  | tname  |
+------+--------+
| t001 | 刘冬   |
| t002 | 刘冬   |
| t003 | 刘冬   |
| t004 | 刘冬   |
| t005 | 刘冬   |
+------+--------+
5 rows in set (0.00 sec)

mysql> select * from h_teacher ;
Empty set (0.01 sec)

mysql> update teacher set tname='刘冬2' where tno='t001';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from h_teacher ;
+------+-----------+-----------+---------------------+
| tno  | new_tname | old_tname | sdate               |
+------+-----------+-----------+---------------------+
| t001 | 刘冬2     | 刘冬      | 2021-05-03 10:56:45 |
+------+-----------+-----------+---------------------+
1 row in set (0.00 sec)

mysql> 

触发器实现的效果,在程序中也能实现,更多的是放在程序中实现,比如写了触发器后期没用维护给忘了,会出现些难排查的场景。

比如程序员不知道有触发器的话,就不会想到主键冲突的原因了。

mysql> show create table teacher;
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                             |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| teacher | CREATE TABLE `teacher` (
  `tno` varchar(10) COLLATE utf8_bin NOT NULL,
  `tname` varchar(20) COLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`tno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> update teacher set tname='刘冬2' where tno='t001';
ERROR 1062 (23000): Duplicate entry 't001' for key 'PRIMARY'
mysql> 

注意事项:比如上面的执行update操作时,与触发器是在同一个事务内的。

 查看创建的触发器

 

 
 
 
 
 
 
 
 
 
 
 
 
原文地址:https://www.cnblogs.com/laonicc/p/14016259.html