MySQL基础(六)流程控制、游标、触发器、窗口函数

news2024/12/25 9:19:48

目录

定义条件与处理程序

定义条件

定义处理程序

流程控制

IF

分支结构之 CASE

 循环结构之LOOP

 循环结构之WHILE

循环结构之REPEAT

跳转语句leave和iterate 

游标

使用游标步骤

 全局变量的持久化

触发器

触发器的使用

查看触发器

删除触发器


定义条件与处理程序

定义条件 是事先定义程序执行过程中可能遇到的问题, 处理程序 定义了在遇到问题时应当采取的处理方 式,并且保证存储过程或函数在遇到警告或错误时能继续执行。这样可以增强存储程序处理问题的能 力,避免程序异常停止运行。

说明:定义条件和处理程序在存储过程、存储函数中都是支持的。

定义条件

定义条件就是给MySQL中的错误码命名,这有助于存储的程序代码更清晰。它将一个 错误名字 和 指定的 错误条件 关联起来。这个名字可以随后被用在定义处理程序的 DECLARE HANDLER 语句中。

DECLARE 错误名称 CONDITION FOR 错误码(或错误条件)

错误码的说明: MySQL_error_code 和 sqlstate_value 都可以表示MySQL的错误。 MySQL_error_code是数值类型错误代码。

sqlstate_value是长度为5的字符串类型错误代码。 

举例

#使用MySQL_error_code
DECLARE Field_Not_Be_NULL CONDITION FOR 1048;
#使用sqlstate_value
DECLARE Field_Not_Be_NULL CONDITION FOR SQLSTATE '23000';

定义处理程序

可以为SQL执行过程中发生的某种类型的错误定义特殊的处理程序。定义处理程序时,使用DECLARE语句 的语法如下:

DECLARE 处理方式 HANDLER FOR 错误类型 处理语句

处理方式:处理方式有3个取值:CONTINUE、EXIT、UNDO。

CONTINUE :表示遇到错误不处理,继续执行。

EXIT :表示遇到错误马上退出。

UNDO :表示遇到错误后撤回之前的操作。MySQL中暂时不支持这样的操作。

错误类型(即条件)可以有如下取值:

SQLSTATE '字符串错误码' :表示长度为5的sqlstate_value类型的错误代码;

MySQL_error_code :匹配数值类型错误代码;

错误名称 :表示DECLARE ... CONDITION定义的错误条件名称。

SQLWARNING :匹配所有以01开头的SQLSTATE错误代码;

NOT FOUND :匹配所有以02开头的SQLSTATE错误代码;

SQLEXCEPTION :匹配所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE错误代码;

处理语句:如果出现上述条件之一,则采用对应的处理方式,并执行指定的处理语句。语句可以是 像“ SET 变量 = 值 ”这样的简单语句,也可以是使用 BEGIN ... END 编写的复合语句。 

举例

delimiter //
create procedure test_fault()
begin
declare continue handler for 1048 set @y=1;
set @x=1;
update employees set email = null where employee_id=101;
set @x=2;
end //

此时y=1,x=2

流程控制

IF

IF 表达式1 THEN 操作1
[ELSEIF 表达式2 THEN 操作2]……
[ELSE 操作N]
END IF

举例 

delimiter //
create procedure IF_TEST()
begin
declare age int default 20;
if age>40
	then select '111';
elseif age>18
	then select '222';
else
	select '333';
end if;
end //

分支结构之 CASE

#情况一:类似于switch
CASE 表达式
WHEN 值1 THEN 结果1或语句1(如果是语句,需要加分号)
WHEN 值2 THEN 结果2或语句2(如果是语句,需要加分号)
...
ELSE 结果n或语句n(如果是语句,需要加分号)
END [case](如果是放在begin end中需要加上case,如果放在select后面不需要)

#情况二:类似于多重if
CASE
WHEN 条件1 THEN 结果1或语句1(如果是语句,需要加分号)
WHEN 条件2 THEN 结果2或语句2(如果是语句,需要加分号)
...
ELSE 结果n或语句n(如果是语句,需要加分号)
END [case](如果是放在begin end中需要加上case,如果放在select后面不需要)

举例

delimiter //
create procedure IF_TEST()
begin
declare a int default 1;
case a
when 0 then select '1111';
when 1 then select '22222';
else select '33333';
end case;
end //

delimiter //
create procedure IF_TEST()
begin
declare a int default 1;
case 
when a = 0 then select '1111';
when a = 1 then select '22222';
else select '33333';
end case;
end //

 循环结构之LOOP

LOOP循环语句用来重复执行某些语句。LOOP内的语句一直重复执行直到循环被退出(使用LEAVE子 句),跳出循环过程。 LOOP语句的基本格式如下:

[loop_label:] LOOP
循环执行的语句
IF XXX
THEN LEAVE loop_label;
END IF;
END LOOP [loop_label]

 loop_label 好像是必须要写,不然无法退出循环

delimiter //
create procedure IF_TEST()
begin
declare a int default 1;
loop_label: LOOP
		set a = a+1;
		if a >= 10
			then leave loop_label;
		end if;
	end LOOP loop_label;
	select a;
end //
delimiter //
create procedure IF_TEST(out num int)
begin
declare a double default 0;
set num = 0;
loop_label: LOOP
	select avg(salary) into a from employees;
	if a >=12000
		then leave loop_label;
	end if;
	update employees set salary = salary*1.1;
	set num = num+1;
	end LOOP loop_label;
end //

 循环结构之WHILE

WHILE语句创建一个带条件判断的循环过程。WHILE在执行语句执行时,先对指定的表达式进行判断,如 果为真,就执行循环内的语句,否则退出循环。WHILE语句的基本格式如下:

[while_label:] WHILE 循环条件 DO
循环体
END WHILE [while_label];
delimiter //
create procedure IF_TEST()
begin
declare a int default 0;
while a<=10 do
    set a=a+1;
end while;
select a;
end //

循环结构之REPEAT

REPEAT语句创建一个带条件判断的循环过程。与WHILE循环不同的是,REPEAT 循环首先会执行一次循 环,然后在 UNTIL 中进行表达式的判断,如果满足条件就退出,即 END REPEAT;如果条件不满足,则会 就继续执行循环,直到满足退出条件为止。

REPEAT语句的基本格式如下:

[repeat_label:] REPEAT
循环体的语句
UNTIL 结束循环的条件表达式
END REPEAT [repeat_label]

注意 until xxx后面不需要加;

delimiter //
create procedure IF_TEST()
begin
	declare a int default 0;
	repeat
		set a=a+1;
		until a>=10
		end repeat;
	select a;
end //

 对比三种循环结构:

1、这三种循环都可以省略名称,但如果循环中添加了循环控制语句(LEAVE或ITERATE)则必须添加名 称。

2、 LOOP:一般用于实现简单的"死"循环 WHILE:先判断后执行 REPEAT:先执行后判

断,无条件 至少执行一次

跳转语句leave和iterate 

leave可以理解为break 

LEAVE 标记名

leave不仅仅可以用在循环体中,也可以用在普通的 begin_end中

DELIMITER //
CREATE PROCEDURE leave_begin(IN num INT)
begin_label: BEGIN
    IF num<=0
        THEN LEAVE begin_label;
    ELSEIF num=1
        THEN SELECT AVG(salary) FROM employees;
    ELSEIF num=2
        THEN SELECT MIN(salary) FROM employees;
    ELSE
        SELECT MAX(salary) FROM employees;
    END IF;
SELECT COUNT(*) FROM employees;
END //

ITERATE语句:只能用在循环语句(LOOP、REPEAT和WHILE语句)内,表示重新开始循环,将执行顺序 转到语句段开头处。如果你有面向过程的编程语言的使用经验,你可以把 ITERATE 理解为 continue,意思为“再次循环”。

delimiter //
create procedure IF_TEST()
begin
	declare a int default 0;
	my_loop:LOOP
	SET a = a+1;
		if a<10
			then iterate my_loop;
		elseif a>15
			then leave my_loop;
		end if;
		
	end loop;
	select a;
end //

游标

虽然我们也可以通过筛选条件 WHERE 和 HAVING,或者是限定返回记录的关键字 LIMIT 返回一条记录, 但是,却无法在结果集中像指针一样,向前定位一条记录、向后定位一条记录,或者是 随意定位到某一 条记录 ,并对记录的数据进行处理。

这个时候,就可以用到游标。游标,提供了一种灵活的操作方式,让我们能够对结果集中的每一条记录 进行定位,并对指向的记录中的数据进行操作的数据结构。游标让 SQL 这种面向集合的语言有了面向过 程开发的能力。

打个比方,如果说我的需求是,工资大于10000的人涨薪1000,其余的人涨薪2000。那么我们必须一个一个定位到每一个员工,这样的操作可以使用游标实现

使用游标步骤

1、 声明游标

DECLARE cursor_name CURSOR FOR select_statement;

2、打开游标

OPEN cursor_name

3、使用游标(从游标中取得数据)

FETCH cursor_name INTO var_name [, var_name] ...

4、关闭游标

CLOSE cursor_name

举个例子

实现循环查看员工的工资,大于10000的涨薪1000,其余的涨薪2000

delimiter //
create procedure TEST()
begin
	declare emp_sal double(8,2) default 0;
	declare flag int default 0;
	declare sal_cursor cursor for select salary from employees;
	
	declare continue handler for NOT FOUND set flag=1;
	open sal_cursor;
	loop_label:LOOP
		if flag>=1
			then leave loop_label;
		end if;
		fetch sal_cursor into emp_sal;
		if emp_sal>10000
			THEN UPDATE employees set salary = salary+1000 where salary = emp_sal;
		else
			UPDATE employees set salary = salary+2000 where salary = emp_sal;
		end if;
	end loop;
	close sal_cursor;
end //

declare continue handler for NOT FOUND set flag=1;

这句话保证了循环完所有数据后能退出循环

游标是 MySQL 的一个重要的功能,为 逐条读取 结果集中的数据,提供了完美的解决方案。跟在应用层 面实现相同的功能相比,游标可以在存储程序中使用,效率高,程序也更加简洁。

但同时也会带来一些性能问题,比如在使用游标的过程中,会对数据行进行 加锁 ,这样在业务并发量大 的时候,不仅会影响业务之间的效率,还会 消耗系统资源 ,造成内存不足,这是因为游标是在内存中进 行的处理。

建议:养成用完之后就关闭的习惯,这样才能提高系统的整体效率。

 全局变量的持久化

之前在设置全局变量的时候,如果重启了sql就会丢失这样的设置

使用SET GLOBAL语句设置的变量值只会 临时生效 。 数据库重启 后,服务器又会从MySQL配置文件中读取 变量的默认值。 MySQL 8.0版本新增了 SET PERSIST 命令。例如,设置服务器的最大连接数为1000:

SET PERSIST global max_connections = 1000;

触发器

触发器是由 事件来触发 某个操作,这些事件包括 INSERT 、 UPDATE 、 DELETE 事件。所谓事件就是指 用户的动作或者触发某项行为。如果定义了触发程序,当数据库执行这些语句时候,就相当于事件发生 了,就会 自动 激发触发器执行相应的操作。

当对数据表中的数据执行插入、更新和删除操作,需要自动执行一些数据库逻辑时,可以使用触发器来 实现。

说到底就是一个监听器,并作出回应。

触发器的使用

CREATE TRIGGER 触发器名称
{BEFORE|AFTER} {INSERT|UPDATE|DELETE} ON 表名
FOR EACH ROW
触发器执行的语句块;

案例1,在test1表插入数据之前,在test2表中插入1

create table test1(
id int primary key auto_increment,
a int
)

CREATE TABLE test2(
id INT PRIMARY KEY AUTO_INCREMENT,
b INT
)

DELIMITER //
create trigger insert_tri
before insert on test1
for each row
begin
	insert into test2(b) values(1);
end //

insert into test1(a) values(222)

select * from test2

案例2,在员工表插入前检查工资是否大于老板的工资,如果是,报错

DELIMITER //
create trigger insert_tri2
before insert on employees
for each row
begin
	declare sal double;
	
	select salary into sal from employees where employee_id = NEW.manager_id;
	if NEW.salary > sal then
		SIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT = '薪资高于领导薪资错误';
		end if;
	
end //

这里使用了 SIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT = '薪资高于领导薪资错误'; 手动触发报错,且使用NEW.获取新加入的数据

查看触发器

 查看触发器是查看数据库中已经存在的触发器的定义、状态和语法信息等。

方式1:查看当前数据库的所有触发器的定义

SHOW TRIGGERS

方式2:查看当前数据库中某个触发器的定义

SHOW CREATE TRIGGER 触发器名

方式3:从系统库information_schema的TRIGGERS表中查询“salary_check_trigger”触发器的信息。

SELECT * FROM information_schema.TRIGGERS

删除触发器

DROP TRIGGER IF EXISTS 触发器名称

新特性1、窗口函数

  对于数据分组处理,我们之前学过了  group by,但是这样会造成一个类别的所有数据都被压缩到一条数据,而无法处理分类别的单个数据处理

举个例子,对于不同种类的商品,我想统计每个商品与同类商品中最贵的商品的差价,那么可能需要根据不同的类别对数据进行单独处理,窗口函数就可以实现。

都是分类,窗口函数分类完,数据条数不变

窗口函数分类

窗口函数可以分为 静态窗口函数 动态窗口函数 。

静态窗口函数的窗口大小是固定的,不会因为记录的不同而不同;

动态窗口函数的窗口大小会随着记录的不同而变化。

语法结构

函数 OVER([PARTITION BY 字段名 ORDER BY 字段名 ASC|DESC])
or
函数 OVER 窗口名 … WINDOW 窗口名 AS ([PARTITION BY 字段名 ORDER BY 字段名 ASC|DESC])

 下面的案例针对这个表进行

序号函数

ROW_NUMBER()函数

ROW_NUMBER()函数能够对数据中的序号进行顺序显示。

举例:查询 goods 数据表中每个商品分类下价格降序排列的各个商品信息。

SELECT ROW_NUMBER() OVER(PARTITION BY category_id ORDER BY price DESC) AS
row_num,id, category_id, category, NAME, price, stock
FROM goods;

 这里主要生成了一个row_num列,用于记录每个类别下的排序序号

RANK()函数

SELECT RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS
row_num,id, category_id, category, NAME, price, stock
FROM goods;

跟上面那个的主要区别是,当遇到price一样的商品,rank函数给予的序号是一样的

 DENSE_RANK()函数

SELECT DENSE_RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS
row_num,id, category_id, category, NAME, price, stock
FROM goods;

 主要区别是,两个89.9元的都序号是2,后面那个序号是3而不是4

分布函数

PERCENT_RANK()函数

PERCENT_RANK()函数是等级值百分比函数。按照如下方式进行计算。

 其中,rank的值为使用RANK()函数产生的序号,rows的值为当前窗口的总记录数。

SELECT PERCENT_RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS pr,
id, category_id, category, NAME, price, stock
FROM goods

 其实就是统计排序在同组中的百分比

 CUME_DIST()函数

查询goods数据表中小于或等于当前价格的比例。

SELECT CUME_DIST() OVER(PARTITION BY category_id ORDER BY price ASC) AS cd,
id, category, NAME, price
FROM goods;

grant all privileges on *.* to root@"%" identified by '123456' with grant option;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/974358.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于 LLM 的知识图谱另类实践

本文整理自社区用户陈卓见在「夜谈 LLM」主题分享上的演讲&#xff0c;主要包括以下内容&#xff1a; 利用大模型构建知识图谱利用大模型操作结构化数据利用大模型使用工具 利用大模型构建知识图谱 上图是之前&#xff0c;我基于大语言模型构建知识图谱的成品图&#xff0c;主…

【Java从0到1学习】14 Java多线程

1. 多线程概述 人们在日常生活中&#xff0c;很多事情都是可以同时进行的。例如&#xff0c;一个人可以一边听音乐&#xff0c;一边打扫房间&#xff0c;可以一边吃饭&#xff0c;一边看电视。在使用计算机时&#xff0c;很多任务也是可以同时进行的。例如&#xff0c;可以一边…

Android逆向学习(番外一)smali2java部分文件无法反编译的bug与修复方法

Android逆向学习&#xff08;番外一&#xff09;smali2java部分文件无法反编译的bug与修复方法 一、前言 昨天我和往常一样准备着android逆向&#xff08;四&#xff09;的博客&#xff0c;结果发现smali2java对某些文件无法进行逆向&#xff0c;我不知道windows会不会产生这…

安全运营中心(SOC)技术框架

2018年曾经画过一个安全运营体系框架&#xff0c;基本思路是在基础单点技术防护体系基础上&#xff0c;围绕着动态防御、深度分析、实时检测&#xff0c;建立安全运营大数据分析平台&#xff0c;可以算作是解决方案产品的思路。 依据这个体系框架&#xff0c;当时写了《基于主动…

C++零碎记录(三)

作者&#xff1a;小王同学在积累 链接&#xff1a;https://www.zhihu.com/question/437657370/answer/1692846096 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 5. 构造函数和析构函数 5.1 构造函数和析构函数的…

史上最全的计算机发展编年史!!!

今天分享给大家&#xff0c;以供参考。 1614年 苏格兰人约翰纳皮尔&#xff08;John Napier&#xff09;发表了一篇论文&#xff0c;其中提到他发明了一种可以计算四则运算和方根运算的精巧装置。 1623年 威廉契克卡德&#xff08;Wilhelm Schickard&#xff09;制作了一个通过…

【从0学习Solidity】2. 值类型详解

Solidity极简入门: 2. 值类型 博主简介&#xff1a;不写代码没饭吃&#xff0c;一名全栈领域的创作者&#xff0c;专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构&#xff0c;分享一些项目实战经验以及前沿技术的见解。关注我们的主页&#xff0c;探索全栈开发…

计算机网络-谢希任第八版学习笔记总结

一.计算机网络概述 21世纪三个特点 数字化 信息化 智能化&#xff0c;其中主要是围绕智能化。 网络的常见分类&#xff1a; 电话网络 有线电视网络 计算机网络 互联网&#xff1a;Internet 由数量极大的计算机网络相连接 特点&#xff1a; 共享性 连通性 互联网&…

MySql学习笔记09——索引介绍

索引 基本概念 通过给字段名上增加索引&#xff0c;可以提高查询的效率。 一张表的一个字段可以添加一个索引&#xff0c;当然&#xff0c;多个字段联合起来也可以添加索引。索引相当于一本书的目录&#xff0c;是为了缩小扫描范围而存在的一种机制。 select * from t_user…

Java“牵手”阿里巴巴商品列表数据,关键词搜索阿里巴巴商品数据接口,阿里巴巴API申请指南

阿里巴巴商城是一个网上购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取阿里巴巴商品列表和商品详情页面数据&#xff0c;您可以通过开放平台的接口或者直接访问阿里巴巴商城的网页来获取商品详情信息。以下是两种常用方…

纯前端实现 导入 与 导出 Excel

最近经常在做 不规则Excel的导入&#xff0c;或者一些普通Excel的导出&#xff0c;当前以上说的都是纯前端来实现&#xff1b;下面我们来聊聊经常用到的Excel导出与导入的实现方案&#xff0c;本文实现技术栈以 Vue2 JS 为例 导入分类&#xff1a; 调用 API 完全由后端来解析数…

学习心得07:C#

之前也没有看过C#的书&#xff0c;C#的程序倒是搞了一些。好在项目不大&#xff0c;我又会套路。 C#很象是JAVA。好像就是JAVA出来之后&#xff0c;微软抄的。好东西就要学习&#xff0c;这不丢脸。 我倒是想&#xff0c;有没有办法把JAVA和C#进行映射&#xff0c;然后直接编译…

优思学院|亲和图案例:寻找六西格玛的项目

什么是亲和图&#xff1f; 亲和图&#xff08;Affinity Diagram&#xff09;主要功能在於分类归纳&#xff0c;协助在一堆杂乱无章的资料之中&#xff0c;有系统的归纳出几个大类&#xff0c;以利后续作业。通常先利用头脑风暴&#xff08;Brainstorming&#xff09;方式得到大…

WhatsApp电子商务,一个划时代的营销工具

WhatsApp电子商务就是使用WhatsApp进行在线购物&#xff0c;企业可以利用其庞大的用户群和可访问性来促进销售并提供客户服务。企业可以创建产品目录供客户浏览和进行产品查询&#xff0c;而订单可以通过WhatsApp消息或自动表格方便地下达&#xff0c;它还通过允许代理商轻松解…

【ccf-csp题解】第0次csp认证-第五题-I‘m stuck!-题解

题目描述 思路讲解 总体步骤 第一步&#xff1a;从起点正向搜索&#xff0c;能到达的地方(x,y)&#xff0c;给st1[x][y]标记为true 第二步&#xff1a;从终点反向搜索&#xff0c;能到达的地方(x,y)&#xff0c;给st2[x][y]标记为true 第三步&#xff1a;设终点位置为&…

【LeetCode】剑指 Offer <二刷>(7)

目录 题目&#xff1a;剑指 Offer 14- I. 剪绳子 - 力扣&#xff08;LeetCode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 题目&#xff1a;剑指 Offer 14- II. 剪绳子 II - 力扣&#xff08;…

基于YOLOv8+PyQt5实现的共享自行车识别检测系统,含数据集+模型+精美GUI界面(可用于违规停放检测告警项目)

系列文章目录 文章目录 系列文章目录前言欢迎来到我的博客&#xff01;我很高兴能与大家分享关于基于YOLOv8的共享自行车识别检测&#xff0c;违规停放告警系统的内容。 一、系统特点7. 带有训练部分标注好的数据集&#xff0c;训练集、验证集 二、环境配置2.anaconda环境导入p…

阿里内部绝密资料——亿级并发系统架构设计(2023版)

俗话说&#xff1a;罗马不是一天建成的&#xff0c;系统的设计当然也是如此。 从原来谁都不看好的淘宝到现在的电商巨头&#xff0c;展现的不仅仅是一家互联网巨头的兴起&#xff0c;也是国内互联网行业迎来井喷式发展的历程&#xff0c;网络信号从 2G 发展到现在的 5G 通信&a…

uniapp移动端地图,点击气泡弹窗并实现精准定位

记录移动端地图map组件的使用 需求记录&#xff1a; 移动端地图部分需要展示两个定位点&#xff0c;上报点及人员定位点。通过右上角的两个按钮实现地图定位。点击对应定位气泡&#xff0c;弹出定位点的信息。 效果图如下&#xff1a; map在nvue中的使用。直接用nvue可以直接…

Python的io模块

io 模块提供了 Python 用于处理各种 I/O 类型的主要工具。三种主要的 I/O类型分别为: 文本 I/O, 二进制 I/O 和 原始 I/O。 io.open() 是内置的 open() 函数的别名. 语法&#xff1a; open(file,moder,buffering-1,encodingNone,errorsNone,newlineNone,closefdTrue,openerN…