目录

Mysql 游标(cursor)

Mysql 视图(View)

Mysql 触发器 trigger

定时任务

创建事件

常见时间调度

精选示例


数据准备sql/mysql/新建书籍与分类表.sql · 汪少棠/material - Gitee.com

Mysql 游标(cursor)

1、游标用于操作查询的结果集,类似 JDBC 的 ResultSet,主要用于存储过程中操作结果数据。

1、定义游标:DECLARE 光标名 CURSOR FOR select 语句;
2、打开游标: open 光标名;
3、取出当前游标指向的行:fetch 光标名 into 其它变量;
4、关闭游标:close 游标名;

2、越界标识:

declare flag int default 1; 
declare continue|exit|undo handler for not found set flag := 0;

# flag 变量声明在游标之前,当游标取值为空时,会触发越界标识,将 flag 置为 0
# continue:后面的语句继续执行
# exit:后面的语句结束
# undo:前面的语句撤销

3、举例如下:

drop procedure if exists param10; #如果存在存储过程 param10,则删除它

delimiter // #临时改变语句结束符
create procedure param10(in total int) #申明存储过程
begin  #开始
declare v_id int; #定义变量,用于接收值
declare v_title varchar(128); #定义变量,用于接收值
declare v_prive float(8,2); #定义变量,用于接收值
declare v_publish date; #定义变量,用于接收值
declare v_info varchar(128); #定义变量,用于接收值
declare flag int default 1; #定义变量,作为结束标识
declare cur_book2 cursor for select * from book_2 limit total; #定义游标
declare exit handler for not found set flag := 0; #设置游标越界标识
open cur_book2; #打开游标
while flag !=0 do # while 循环,flag 不等于0时,一直循环,等于0时推出
    fetch cur_book2 into v_id,v_title,v_prive,v_publish,v_info; #获取游标当前记录的值赋值给变量
    select v_id,v_title,v_prive,v_publish,v_info from dual; #获取变量的值
end while; #循环结束
close cur_book2; #关闭游标
end // #结束
delimiter ; #重新设置语句结束符号为 ";"

call param10(3); #调用存储过程

Mysql 视图(View)

1、视图是一个虚拟表,其内容由查询定义,同真实的表一样,视图包含一系列带有名称的列和行数据。

create [or replace] view 视图名 as 查询语句;

create [algorithm=undefined | merge | temptable] view 视图名 as 查询语句;

创建视图,[or replace] 表示存在时,则替换
alter [or replace] view 视图名 as 查询语句 ;修改视图
drop view 视图名 ;删除视图
-- 查询每个书籍及其类型,使用视图
CREATE OR REPLACE VIEW vw_book AS SELECT
	t1.id,
	t1.title,
	t1.price,
	t1.publish,
	t1.info,
	t2.NAME AS 'type'
FROM book t1 LEFT JOIN book_type t2 ON t1.type_id = t2.id;
SELECT * FROM vw_book; -- 查询视图

3、视图引用方式(算法)有三种,[algorithm = {undefined | merge | temptable}]:

undefined:默认为 undefined,表示由系统选择,一般是 merge
merge:会将查询视图的语句与视图定义 where 合并起来
temptable: 视图的结果将被置于临时表中,然后使用它执行语句
navicat 工具中,选择设计视图,高级选项中可以看到详细设置

Mysql 触发器 trigger

数据准备sql/mysql/新建学生与班级表.sql · 汪少棠/material - Gitee.com

1、很多关系数据库中都提供一种技术,可以在用户进行某种操作的时候,自动的进行另外一个操作,这种技术称为触发器技术.

2、触发器是指存放在数据库中,被隐含执行的存储过程,可以支持 dml 触发器,还支持基于系统事件(启动数据库,关闭数据库,登陆)和 ddl 操作建立触发器。

创建触发器

create trigger 触发器名称 after|before insert|update|delete on 表名 for each row
begin
    --sql语句...;

    --new 关键字:当触发插入(insert)和更新(update)事件时可用,指向的是被操作的新记录
    --old 关键字:当触发删除(delete)和更新事件时可用,指向的是被操作的旧记录
edn;

查看触发器show triggers;
删除触发器drop trigger 触发器名

示例1:student 表插入数据时触发

drop trigger if exists tri_insert_student; # 当存储触发器 tri_insert_student 时,删除它
# 创建触发器:当 student 表新增学生时,往班级表 classes 对应的班级人数加 1
delimiter // #临时修改语句结束符为 "//"
create trigger tri_insert_student after insert on student for each row #创建触发器
begin #开始
update classes set total = total + 1 where name = new.classes_name; #sql操作
end // #结束
delimiter ; # 再将结束符修改为分号


drop trigger if exists tri_update_classes; # 当存储触发器 tri_update_classes 时,删除它
# 创建触发器:当新增时,如果没有 info 为 null,则默认让它等于 '尖子班'。
# Mysql 无法像 Oralce 一样设置在新增和更新操作时同时触发.
delimiter // #临时修改语句结束符为 "//"
create trigger tri_update_classes BEFORE INSERT on classes for each row #创建触发器
begin #开始
	IF new.info IS NULL THEN
		set new.info = '尖子班'; # 修改即将插入的字段值.
  END IF;
end // #结束
delimiter ; #再将结束符号修改回分号

示例2:student 表删除数据时触发

drop trigger if exists tri_delete_student; # 当存储触发器 tri_delete_student 时,删除它
# 创建触发器,当 student 表删除学生时,往班级表 classes 对应的班级人数减 1
delimiter // #临时修改语句结束符为 "//"
create trigger tri_delete_student after delete on student for each row #创建触发器
begin #开始
	update classes set total = total - 1 where name = old.classes_name; #sql操作
end // #结束
delimiter ; #再将结束符号修改回分号

示例3:更新操作后触发,将修改前的数据备份到 his 表 

-- 创建备份表
create table dept_his as SELECT * from dept where 1=2;

-- 创建触发器,更新操作后触发,将修改前的数据备份到 his 表
DELIMITER //
CREATE TRIGGER TRIG_dept_Update
AFTER UPDATE ON dept
FOR EACH ROW
BEGIN
  INSERT INTO dept_his (deptno,dname,loc) VALUES (OLD.deptno,OLD.dname,OLD.loc);
END //
DELIMITER ;

定时任务

1、Mysql 事件是一种在特定时间点自动执行的数据库操作,也可以称呼为定时任务,它可以自动执行更新数据、插入数据、删除数据等操作,无需人工干预。创建事件或定时任务可以解决很多重复性工作,配合着动态 sql 和存储过程能起到实时更新数据功能,不需要人工干预,提高了工作效率

  • 自动化: 可以定期执行重复性的任务,无需手动干预。

  • 灵活性: 可以根据需求定制事件,灵活控制任务的执行时间和频率。

  • 提高效率: 可以在非高峰时段执行耗时任务,减少对数据库性能的影响。

2、常见的应用场景有定时备份数据库,清理和统计数据。

查看事件:

-- 查看事件调度器是否开启:ON 表示已开启。
show variables like '%event_scheduler%';

set global event_scheduler = ON; # 开启事件调度器
set global event_scheduler = OFF; # 关闭事件调度器

-- 使用 show 或者 select 语句查看当前数据库中所有的事件
show events;
select * from information_schema.events;

启动事件:alter event event_name enable;

关闭事件:alter event event_name disable;

删除事件:drop event [if exists] event_name;

创建事件

1、create event 创建事件基本语法:

create
    [definer = user]  # 可选,用于定义事件执行时检查权限的用户
    event
    [if not exists]  # 可选,一般都加上,用于判断要创建的事件是否存在
    event_name  # 是用来唯一标识事件的名称。在同一个数据库中,事件名称必须是唯一的。
    on schedule schedule_body  # 用于定义执行的时间和时间间隔
    [on completion [not] preserve]  # 可选,指定事件是否循环执行,默认为一次执行,即 not preserve。
    [enable | disable | disable on slave]  # 可选,指定事件的一种属性,enable 表示启动,disable 表示关闭或者下线,disable on slave 表示从属性上禁用,默认启动
    [comment 'comment']  # 可选,添加事件的注释
    # 必选,event_body 用于指定事件启动时所要执行的代码,
    # 可以是任何有效的sql 语句、存储过程或者一个计划执行的事件。
    # 如果包含多条语句,可以使用 begin … end 复合结构。
    do event_body; 

2、schedule_body 语法:

at timestamp [+ interval interval] ... | every interval
   [starts timestamp [+ interval interval] ...]
   [ends timestamp [+ interval interval] ...]

# 相当于“三周两天后”。此类子句的每个部分必须以+ interval。
at current_timestamp + interval 3 week + interval 2 day

2.1、at timestamp:用于一次性活动,指定事件仅在 timestamp 给出的日期和时间执行一次,时间戳必须同时包含日期和时间,或者必须是解析为日期时间值的表达式,如果日期已过,则会出现警告。

2.2、every interval:每隔一段时间执行事件,指定时间区间内每隔多长时间发生一次,interval 其值由一个数值和单位(quantity)组成,格式如下,如 4 week 表示 4 周,’1:10’ HOUR_MINUTE 表示1小时10分钟。

interval:
	quantity {year | quarter | month | day | hour | minute |
			week | second | year_month | day_hour | day_minute |
			day_second | hour_minute | hour_second | minute_second}

2.3、starts timestamp:指定事件的开始时间,timestamp 为时间戳,日期时间值表达式。

2.4、ends timestamp:指定事件的结束时间,timestamp 为时间戳,日期时间值表达式。

常见时间调度

示例描述
on schedule every 30 minute# 每30分钟执行一次,任务创建时立刻会执行一次。
on schedule every 1 hour
  starts '2024-01-03 18:00:00'
# 从 2024-01-03 18:00:00 开始,每1小时执行一次
on schedule every 12 hour
    starts current_timestamp + interval 30 minute
    ends current_timestamp + interval 4 week
# 从现在起30分钟后开始,四周后结束,这段期间内每12小时执行一次

精选示例

# 新建表
drop table if exists face_sales_data;
create table if not exists face_sales_data
(
    sales_date date comment '销售日期',
    order_code varchar(255) comment '订单编码',
    user_code varchar(255) comment '客户编号',
    product_name varchar(255) comment '产品名称',
    sales_province varchar(255) comment '销售省份',
    sales_number int comment '销量',
    create_time datetime default current_timestamp comment '创建时间',
    update_time datetime default current_timestamp on update current_timestamp comment '更新时间'
);

示例1:构造实时数据,需求:每分钟录入关于产品、省份的订单销售数据。

-- 如果任务已经存在,则先删除
drop event if exists face_sales_data_task1;

-- #将sql语句的结束符由默认的分号";"临时改为"//"(可以自定义符号),这样里面才能正常使用分号";",否则会被当做结束符处理。
delimiter //  

# 创建事件任务,多条语句用 begin ... end; 包住。
create event if not exists face_sales_data_task1
on schedule every 1 minute
# starts '2024-01-14 17:35:00'
on completion preserve enable
do
begin
    set @user_code = floor(rand()*900000000 + 100000000);-- 随机生成用户编码,
    set @order_code = md5(floor(rand()*900000000 + 100000000));-- 根据随机用户编码加密成编码
		-- 随机从中选择产品
    set @product_name = ELT(CEILING(RAND() * 8) ,'iPhone 15','iPhone 15 Pro','iPhone 15 Pro Max','Xiaomi 14','Xiaomi 14 Pro','Huawei Mate 60','Huawei Mate 60 Pro','Huawei Mate 60 Pro+');-- 随机从中选择产品
    -- 随机从中选择省份
		set @sales_province = ELT(CEILING(RAND() * 34) ,'河北省','山西省','辽宁省','吉林省','黑龙江省','江苏省','浙江省','安徽省','福建省','江西省','山东省','河南省','湖北省','湖南省','广东省','海南省','四川省','贵州省','云南省','陕西省','甘肃省','青海省','台湾省','内蒙古自治区','广西壮族自治区','西藏自治区','宁夏回族自治区','新疆维吾尔自治区','北京市','上海市','天津市','重庆市','香港特别行政区','澳门特别行政区');
    set @sales_number = floor(rand()*1000);-- 随机生成销量
    select @user_code,@order_code,@product_name,@sales_province,@sales_number;-- 查看生成的数据
		-- 数据录入
    insert into face_sales_data(sales_date, order_code, user_code, product_name, sales_province, sales_number)
    values (curdate(),@order_code,@user_code,@product_name,@sales_province,@sales_number);
end; 

//  # 结束
delimiter ; #将语句的结束符号恢复为分号

-- 过一段时间再一次查看表,可以发现每条记录 create_time 相差1,说明任务调度设置成功,这样就可以自动模拟实时销售数据啦。
select * from face_sales_data;

示例2: 调用存储过程

drop procedure if exists hello_world; -- 如果存在指定的存储过程,则删除
#将sql语句的结束符由默认的分号";"临时改为"$$"(可以自定义符号),这样里面才能正常使用分号";",否则会被当做结束符处理
delimiter $$
create procedure hello_world(in id int) # 声明存储过程
begin  # 开始
    set @user_code = floor(rand()*900000000 + 100000000);-- 随机生成用户编码,
    set @order_code = md5(floor(rand()*900000000 + 100000000));-- 根据随机用户编码加密成编码
		-- 随机从中选择产品
    set @product_name = ELT(CEILING(RAND() * 8) ,'iPhone 15','iPhone 15 Pro','iPhone 15 Pro Max','Xiaomi 14','Xiaomi 14 Pro','Huawei Mate 60','Huawei Mate 60 Pro','Huawei Mate 60 Pro+');-- 随机从中选择产品
    -- 随机从中选择省份
		set @sales_province = ELT(CEILING(RAND() * 34) ,'河北省','山西省','辽宁省','吉林省','黑龙江省','江苏省','浙江省','安徽省','福建省','江西省','山东省','河南省','湖北省','湖南省','广东省','海南省','四川省','贵州省','云南省','陕西省','甘肃省','青海省','台湾省','内蒙古自治区','广西壮族自治区','西藏自治区','宁夏回族自治区','新疆维吾尔自治区','北京市','上海市','天津市','重庆市','香港特别行政区','澳门特别行政区');
    set @sales_number = floor(rand()*1000);-- 随机生成销量
    select @user_code,@order_code,@product_name,@sales_province,@sales_number;-- 查看生成的数据
		-- 数据录入
	  insert into face_sales_data(sales_date, order_code, user_code, product_name, sales_province, sales_number)
    values (curdate(),@order_code,@user_code,@product_name,@sales_province,@sales_number);
end $$ # 结束
delimiter ;  #将语句的结束符号恢复为分号

drop event if exists get_hello_world_task1; # 如果任务已经存在则先删除
create event if not exists get_hello_world_task1 # 如果任务不经存在则创建
	on schedule every 1 minute  # 每隔1分钟执行一次
	starts current_timestamp  # 立刻开始执行
	ends current_timestamp + interval 1 week # 1周后结束
	on completion preserve enable
	do call hello_world(111); # 调用存储过程

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐