少有人走的路中,有这样一句话,一辈子真的很短,远没有我们想象的那么长,永远真的没有那么远。
人这一生很短,我们需要清醒地活着。人在世上活着,会面临许多选择和决定,也会遭遇困境和疑惑。
有人被欲望蒙蔽了双眼,做了错误的决定,遗憾终身,一个活得通透的人。
我有这三次觉醒,人身难得而易失,良时易往而难追,人这一辈子,最大的财富是拥有一个健康的身体。
人生的第一个觉醒:金钱永远没有健康重要。
每个人来到世上,都是唯一的,无论用多少财富都换不来。
金钱名利都是虚妄,生不带来,死不带去,百年之后都会烟消云散,化作黄土。叔本华曾说:
“人类所能犯的最大错误,就是拿健康来换取其他身外之物。”世上钱多赚不完,随富随贫且随喜。
—————— 一禅心灵庙语
解决复杂问题不可能通过一个 SQL
语句完成,我们需要执行多个 SQL
操作。流程控制语句的作用就是 控制存储过程或存储函数 中 SQL语句的执行顺序 。是我们完成复杂操作必不可少的一部分,只要是执行的程序。
流程就分为三大类:
顺序结构
: 程序从上往下依次执行分支结构
:程序按条件进行选择执行,从两条或多条路径中选择一条执行循环结构
: 程序满足一定条件下,重复执行一组语句注意: 针对于MySQL的流程控制语句主要有 3 类
条件判断语句
:IF语句和 CASE 语句循环语句
: LOOP,WHILE 和 REPEAR 语句跳转语句
: ITERATE 和 LEAVE 语句IF 的作用和 Java ,C语言中的 作用是一样的,表达式为真,执行IF包含的语句
格式如下:
IF 表达式1 THEN 表达式1为真 执行该语句
[ELSEIF 表达式2 THEN 表达式2为真,执行该语句]
[ELSE (上述条件都不满足)执行该语句]
END IF; -- if 作用范围结束
根据表达式的结果为 TRUE
或 FALSE
执行相应的语句。这里 其中的“[ ] ”中的内容是可选的,
特点:1. 不同的表达式对应不同的操作,2.使用在 begin...end
中
一选一,满足条件为真,执行
-- 一选一,满足条件执行
DELIMITER $
CREATE PROCEDURE test_if1()
BEGIN
-- 声明局部变量,局部变量必须在begin...end最开始位置声明
DECLARE stu_name VARCHAR(15); -- 没有default 默认是 null
IF stu_name IS NULL
THEN SELECT 'stu_name is null';
END IF; -- if 作用域结束
END $
DELIMITER ;
-- 调用存储过程
CALL test_if1();
二选一,满足条件为真,执行
-- 二选一,满足条件执行
DELIMITER $
CREATE PROCEDURE test_if2()
BEGIN
-- 声明局部变量,局部变量必须在begin...end最开始位置声明
DECLARE stu_name VARCHAR(15) DEFAULT 'hello'; -- default设定默认值
IF stu_name IS NULL
THEN SELECT 'stu_name is null';
ELSE -- 否则
SELECT 'stu_name is not null ';
END IF; -- if 作用范围,结束
END $
DELIMITER ;
-- 调用存储过程
CALL test_if2();
多选一,满足条件为真,执行
-- 多选一,满足条件执行
DELIMITER $
CREATE PROCEDURE test_if3()
BEGIN
-- 声明局部变量,局部变量必须在begin...end最开始位置声明
DECLARE age INT DEFAULT 19; -- default设定默认值
IF age > 40
THEN SELECT '中壮年';
ELSEIF age > 18
THEN SELECT '青壮年';
ELSEIF age > 8
THEN SELECT '青少年';
ELSE
SELECT '婴幼儿';
END IF; -- if 作用范围,结束
END $
DELIMITER ;
-- 调用存储过程
CALL test_if3();
举例: 声明存储过程“update_salary_by_eid3”,定义IN参数emp_id,输入员工编号。判断该员工 薪资如果低于9000元,就更新薪资为9000元;薪资如果大于等于9000元且低于10000的,但是奖金 比例为NULL的,就更新奖金比例为0.01;其他的涨薪100元。
SELECT *
FROM employees
WHERE employee_id IN (102,103,104);
DELIMITER $
CREATE PROCEDURE update_salary_by_eid3(IN emp_id INT)
BEGIN
-- 声明局部变量,必须在begin...end最开始位置
DECLARE emp_sal DOUBLE; -- 记录员工工资
DECLARE bonus DOUBLE; -- 记录员工的奖金率
-- 赋值
SELECT salary INTO emp_sal
FROM employees
WHERE employee_id = emp_id;
SELECT commission_pct INTO bonus
FROM employees
WHERE employee_id = emp_id;
IF emp_sal < 9000
THEN UPDATE employees
SET salary = 9000
WHERE employee_id = emp_id;
ELSEIF emp_sal >= 9000 AND emp_sal < 10000 AND bonus IS NULL
THEN UPDATE employees
SET commission_pct = 0.01
WHERE employee_id = emp_id;
ELSE
UPDATE employees
SET salary = salary + 100
WHERE employee_id = emp_id;
END IF; -- if语句作用范围,结束
END $
DELIMITER ;
调用存储过程
-- 调用存储过程
CALL update_salary_by_eid3(102);
-- 调用存储过程
CALL update_salary_by_eid3(104);
SELECT *
FROM employees
WHERE employee_id IN (102,103,104);
-- 调用存储过程
CALL update_salary_by_eid3(103);
SELECT *
FROM employees
WHERE employee_id IN (102,103,104);
分支结构 case 表示多分支结构 ,一个信息多个值,或者多个范围,多种情况
格式如下:
情况一:类似于 switch
-- 情况一:类似于 switch
CASE 表达式
WHEN 值1 THEN 结果1或语句1(如果是语句,需要加上分号)
WHEN 值2 THEN 结果2或语句2(如果是语句,需要加上分号)
WHEN 值3 THEN 结果3或语句3(如果是语句,需要加上分号)
END CASE; -- 如果是放在begin...end中需要加上case,如果放在select后面不需要加case)
情况二: 类似于多重if
-- 情况二: 类似于多重if
CASE
WHEN 条件1 THEN 结果1或语句1(如果是语句,需要加上分号)
WHEN 条件2 THEN 结果2或语句2(如果是语句,需要加上分号)
WHEN 条件3 THEN 结果3或语句3(如果是语句,需要加上分号)
END CASE; -- 如果是放在begin...end中需要加上case,如果放在select后面不需要加case)
举例情况1: 创建存储过程 test_case( )
DELIMITER //
CREATE PROCEDURE test_case()
BEGIN
-- 声明局部变量,必须在begin...end最开始位置
DECLARE var INT DEFAULT 2; -- default 设定默认值
CASE var
WHEN 1 THEN SELECT 'var = 1'; -- 如果是语句需要加上分号
WHEN 2 THEN SELECT 'var = 2';
WHEN 3 THEN SELECT 'var = 3';
ELSE SELECT 'other value';
END CASE; -- case 作用范围结束
END //
DELIMITER ;
-- 调用存储过程
CALL test_case();
举例情况2 创建存储过程 test_case2( )
DELIMITER $
CREATE PROCEDURE test_case2()
BEGIN
-- 声明局部变量,必须在beign...end最开始位置
DECLARE var INT DEFAULT 10; -- defualt设定默认值为 10
CASE
WHEN var >= 100 THEN SELECT '三位数';
WHEN var >= 10 THEN SELECT '两位数';
ELSE SELECT '个数位';
END CASE ; -- case 作用范围结束,case在begin...end需要指明case标签,在select 中不用
END $
DELIMITER ;
-- 调用存储过程
CALL test_case2();
LOOP
循环语句用来重复执行某些语句。LOOP
内的语句一直重复执行直到 循环被退出**(使用 LEAVE
于Java中的 break 作用是一样的)**。跳出循环过程。其实 LOOP
和 C语言中的 goto
类似,和 Java中的 goto
也类似
LOOP
语句的基本格式如下:
xxx:LOOP -- xxx 表示标签,用于 loop 的跳转,和 leave 的跳出
循环执行语句
IF 条件
THEN LEAVE xxx; -- 跳出该 loop 循环体,xxx 表示标签
END LOOP xxx; -- loop 作用范围,结束,xxx 表示标签
举例: 使用LOOP语句进行循环操作,id值小于10时将重复执行存储函数。
-- 存储函数的参数配置
SET GLOBAL log_bin_trust_function_creators = 1;
DELIMITER //
CREATE FUNCTION test_loop()
RETURNS INT -- 返回的数据类型,多个s,不要加;分号
BEGIN
-- 声明局部变量,必须在begin...end最开始位置
DECLARE num INT DEFAULT 1; -- default 设定初始值为 1
loop_label:LOOP -- loop_label 标签
SET num = num + 1;
IF num >= 10
THEN LEAVE loop_label; -- levae 跳出标签loop_label循环体
END IF; -- if作用范围,结束
END LOOP loop_label; -- loop 作用范围,结束
RETURN num; -- 返回数值
END //
DELIMITER ;
-- 调用存储函数
SELECT test_loop();
举例: 当市场环境变好时,公司为了奖励大家,决定给大家涨工资。声明存储过程“update_salary_loop()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家涨薪,薪资涨为 原来的1.1倍。直到全公司的平均薪资达到12000结束。并统计循环次数。
DELIMITER $
CREATE PROCEDURE update_salary_loop(OUT num INT)
BEGIN
-- 声明局部变量,必须在begin...end最开始位置
DECLARE avg_sal DOUBLE; -- 员工的平均工资
DECLARE loop_count INT DEFAULT 0; -- 记录循环次数,必须赋值default
-- 不然默认为 null,任何数与 null 计算都为 null,无法起到累加的作用
SELECT AVG(salary) INTO avg_sal
FROM employees;
loop_lable:LOOP -- loop_lable 标签,用于leave 跳出循环体
IF avg_sal >= 12000
THEN LEAVE loop_lable; -- 跳出loop_lable 循环体
END IF; -- if 作用范围,结束
UPDATE employees
SET salary = salary * 1.1;
SELECT AVG(salary) INTO avg_sal
FROM employees;
SET loop_count = loop_count + 1;
END LOOP loop_lable; -- loop 作用范围,结束
SET num = loop_count;
END $
DELIMITER ;
调用存储过程
-- 调用存储过程;
SET @num = 0;
CALL update_salary_loop(@num);
SELECT @num; -- 查看会话用户变量,循环了几次
查询表,验证结果
SELECT AVG(salary)
FROM employees;
WHILE
语句创建一个带条件判断的循环过程。WHILE 在执行语句执行时,先对指定的表达式进行判断,如果为真,就执行循环内的语句,否则退出循环。WHILE 语句的基本格式如下:
WHILE 循环条件 DO -- 如果循环条件结果为真,WHILE语句内的语句或语句群被执行,直
-- 至循环条件为假,退出循环。
... 循环体
END WHILE; -- while 作用范围,结束
举例: WHILE语句示例,i值小于10时,将重复执行循环过程,代码如下:
DELIMITER $
CREATE PROCEDURE test_while()
BEGIN
-- 声明局部变量,必须在begin...end最开始位置,不然报错
DECLARE i INT DEFAULT 1; -- 必须赋予defualt 初始值,不然为null,任何数与null计算
-- 都为 null,无法累加
WHILE i <= 10 DO
SET i = i + 1;
END WHILE ; -- while 作用范围,结束
SELECT i;-- 查看局部变量的值,作用范围在begin...end语句块内
END $
DELIMITER ;
-- 调用存储过程
CALL test_while();
举例: 市场环境不好时,公司为了渡过难关,决定暂时降低大家的薪资。声明存储过程“update_salary_while()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家降薪,薪资降 为原来的90%。直到全公司的平均薪资达到5000结束。并统计循环次数。
DELIMITER //
CREATE PROCEDURE update_salary_while(OUT num INT)
BEGIN
-- 声明局部变量,必须在begin...end最开始位置,不然报错
DECLARE avg_sal DOUBLE; -- 举例平均工资
DECLARE while_count INT DEFAULT 0; -- 记录循环次数,
-- 注意必须default 赋予初始值,不然为 null,任何数与 null,都为 null,无法累加
-- 赋值
SELECT AVG(salary) INTO avg_sal
FROM employees;
WHILE avg_sal >= 6000 DO
SET while_count = while_count + 1;
UPDATE employees
SET salary = salary *0.9;
SELECT AVG(salary) INTO avg_sal
FROM employees;
END WHILE; -- while 作用范围,结束
SET num = while_count;
END //
DELIMITER;
调用存储过程
-- 调用存储过程
SET @num = 0;
CALL update_salary_while(@num);
SELECT @num; -- 查看循环次数
查询验证是否成功
SELECT AVG(salary)
FROM employees;
REPEAT
语句创建一个带条件判断的循环过程。与 WHILE
循环不同的时,REPEAT
循环首先会执行一次循环,然后在 UNTIL
中进行表达式的判断,如果满足条件就退出,注意是满足条件退出,同时在 UNTIL
语句的后面不要加 ;分号 。即 END REPEAT
,如果条件不满足,则会就继续执行循环,直到满足退出条件为止。
具体格式如下:
REPEAT
循环体语句
UNTIL 结束循环的条件表达式
END REPEAT; -- repeat 作用范围,结束
**举例: ** REPEAT 语句示例,i值小于10时,将重复执行循环过程,代码如下:
DELIMITER //
CREATE PROCEDURE test_repeat()
BEGIN
-- 声明局部变量,必须在begin...end最开始位置,不然报错
DECLARE i INT DEFAULT 0; -- 必须default 默认初始值,不然为 null,任何数值与 null,运算都为 null
REPEAT
SET i = i + 1;
UNTIL i >= 10 -- 满足条件跳出循环,不要加;分号
END REPEAT; -- repeat 作用范围,结束
SELECT i ; -- 查询局部变量的值,作用范围在begin...end语句块内
END //
DELIMITER ;
-- 调用存储过程
CALL test_repeat();
举例: 当市场环境变好时,公司为了奖励大家,决定给大家涨工资。声明存储过程“update_salary_repeat()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家涨薪,薪资涨 为原来的1.15倍。直到全公司的平均薪资达到13000结束。并统计循环次数。
DELIMITER $
CREATE PROCEDURE update_salary_repeat(OUT num INT)
BEGIN
-- 声明局部变量,必须在begin...end首行位置
DECLARE avg_sal DOUBLE ; -- 记录平均工资
DECLARE repeat_count INT DEFAULT 0; -- 记录循环次数
-- 必须defualt 初始化默认值,不然为 null,任何数与 null运算都为 null,无法累加
REPEAT
-- 赋值
SELECT AVG(salary) INTO avg_sal
FROM employees;
UPDATE employees
SET salary = salary *1.15;
SET repeat_count = repeat_count + 1;
UNTIL avg_sal >= 13000 -- 满足条件,退出循环,不要加分号,不然报错
END REPEAT; -- repeat 作用范围,结束
SET num = repeat_count;
END $
DELIMITER ;
调用存储过程,查询循环次数
-- 调用存储过程
SET @num = 0;
CALL update_salary_repeat(@num);
SELECT @num;
查询表,验证是否涨薪成功
SELECT AVG(salary)
FROM employees;
LEAVE(break)
或ITERATE(continue)
)则必须添加名称标签。LOOP
:一般用于实现简单的 “无限循环”WHILE
: 先判断后执行REPEAT
先执行后判断,无论如何都会至少执行一次循环体LEAVE
语句:可以用在循环语句 内,或者以 BEGIN
和 END
包裹起来的程序体内,表示跳出循环或者跳出程序体的操作。可以把 LEAVE
理解成是 C语言中或者是Java语言中的 break
。
基本格式如下
LEAVE 标记名;
LEAVE
往往配合 IF
条件判断一起使用。以及和BEGIN … END或循环一起被使用。
举例: 创建存储过程 “leave_begin()”,声明INT类型的IN参数num。给BEGIN…END加标记名,并在BEGIN…END中使用IF语句判断num参数的值。
IF语句结束后查询“employees”表的总人数。
注意:使用 LEAVE
跳转语句需要定义标签
DELIMITER $
CREATE PROCEDURE leave_begin(IN num INT)
begin_label:BEGIN -- begin_label 是标签
IF num < 0
THEN LEAVE begin_label; -- break 结束该标签下的循环
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; -- if 作用范围,结束
-- 查询总人数
SELECT COUNT(*)
FROM employees;
END $
DELIMITER ;
-- 调用存储过程
CALL leave_begin(1);
举例: 当市场环境不好时,公司为了渡过难关,决定暂时降低大家的薪资。声明存储过程“leave_while()”,声明OUT参数num,输出循环次数,存储过程中使用WHILE循环给大家降低薪资为原来薪资的90%,直到全公 司的平均薪资小于等于10000,并统计循环次数。
注意:使用 LEAVE
跳转语句需要定义标签
DELIMITER //
CREATE PROCEDURE leave_while(OUT num INT)
BEGIN
-- 声明局部变量,必须在begin...end最开始位置,不然报错
DECLARE avg_sal DOUBLE; -- 记录平均工资
DECLARE while_count INT DEFAULT 0; -- 记录循环次数,必须default 设定默认初始值,不然为 null
-- 赋值
SELECT AVG(salary) INTO avg_sal
FROM employees;
-- 任何数与 null 运算都为 null
while_lable:WHILE TRUE DO -- true 为真,死循环
IF avg_sal < 10000
THEN LEAVE while_lable; -- break 跳出该标签循环
END IF; -- if 作用范围结束
UPDATE employees
SET salary = salary *0.9;
SET while_count = while_count + 1;
SELECT AVG(salary) INTO avg_sal
FROM employees;
END WHILE while_lable ; -- while作用范围,结束
SET num = while_count;
END //
DELIMITER ;
-- 调用存储过程
SET @num = 0; -- 会话用户变量必须赋予初始值,不然报错
CALL leave_while(@num);
SELECT @num ;
查看验证
SELECT AVG(salary)
FROM employees;
ITERATE
语句:只能用在循环语句 ( LOOP,REPEAT 和 WHILE 语句
) 内,表示重新开始循环,将执行顺序转到语句段开头处。可以把 ITEREATE
理解为 C语言和Java语言中的 continue
跳出本次循环。
基本格式如下:
ITERATE label;
label
参数表示循环的标志。ITERATE
语句必须跟在循环标志前面。
举例: 定义局部变量num,初始值为0。循环结构中执行num + 1操作。
DELIMITER //
CREATE PROCEDURE test_iterate()
BEGIN
-- 声明局部变量,必须在begin...end最开始位置,不然报错
DECLARE num INT DEFAULT 1; -- 必须default 不然默认为null,任何数与 null 都是null
-- 就无法起到累加的效果了
loop_label:LOOP
SET num = num + 1;
IF num < 10
THEN ITERATE loop_label; -- contniue 跳过本次标签loop_label循环
ELSEIF num > 15
THEN LEAVE loop_label; -- break 跳出标签loop_label 循环
END IF; -- if 作用范围,结束
SELECT '尚硅谷,让天下没有难学的技术';
END LOOP loop_label; -- loop 循环作用范围,结束
END //
DELIMITER ;
-- 调用存储过程
CALL test_iterate();
再使用 while 的循环语句实现
DELIMITER //
CREATE PROCEDURE test_while_iterate()
BEGIN
-- 声明局部变量,局部变量必须在begin...end最开始位置,不然报错
DECLARE num INT DEFAULT 0; -- 必须default设定初始值,不然为null,任何数与null 结果都为 null
while_lable:WHILE TRUE DO -- true 为真,这里while 无限循环
SET num = num +1;
IF num < 10
THEN ITERATE while_lable; -- iterate 跳过本次 while_lable 标签循环
ELSEIF num > 15
THEN LEAVE while_lable; -- leave 跳出while_lable 标签循环
END IF; -- if 作用范围,结束
SELECT '尚硅谷,让天下没有难学的技术';
END WHILE; -- while 作用范围,结束
END //
DELIMITER ;
-- 调用存储过程
CALL test_while_iterate();
限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,后会有期,江湖再见 !!!