起步
| 顺序结构 :程序从上往下依次执行 |
| 分支结构 :程序按条件进行选择执行,从两条或多条路径中选择一条执行 |
| 循环结构 :程序满足一定条件下,重复执行一组语句 |
| |
| 针对于MySQL 的流程控制语句主要有 3 类。注意:只能用于存储程序 |
| 条件判断语句 :IF 语句和 CASE 语句 |
| 循环语句 :LOOP、WHILE 和 REPEAT 语句 |
| 跳转语句 :ITERATE 和 LEAVE 语句 |
IF
| IF 表达式1 THEN 操作1 |
| [ELSEIF 表达式2 THEN 操作2]…… |
| [ELSE 操作N] |
| END IF |
| # 举例1 |
| DELIMITER // # 开始 |
| CREATE PROCEDURE test_if() # 创建存储过程 |
| BEGIN |
| #情况1: |
| #声明局部变量 |
| #declare stu_name varchar(15); |
| |
| #if stu_name is null |
| # then select 'stu_name is null'; |
| #end if; |
| |
| #情况2:二选一 |
| #declare email varchar(25) default 'aaa'; |
| |
| #if email is null |
| # then select 'email is null'; |
| #else |
| # select 'email is not null'; |
| #end if; |
| |
| #情况3:多选一 |
| DECLARE age INT DEFAULT 20; |
| |
| IF age > 40 |
| THEN SELECT '中老年'; |
| ELSEIF age > 18 |
| THEN SELECT '青壮年'; |
| ELSEIF age > 8 |
| THEN SELECT '青少年'; |
| ELSE |
| SELECT '婴幼儿'; |
| END IF; |
| END // |
| DELIMITER ; |
| |
| #调用 |
| CALL test_if(); |
| |
| # 举例2:声明存储过程“update_salary_by_eid1”,定义IN参数emp_id,输入员工编号。判断该员工薪资如果低于8000元并且入职时间超过5年,就涨薪500元;否则就不变。 |
| DELIMITER // |
| CREATE PROCEDURE update_salary_by_eid1(IN emp_id INT) |
| BEGIN |
| #声明局部变量 |
| DECLARE emp_sal DOUBLE; #记录员工的工资 |
| DECLARE hire_year DOUBLE; #记录员工入职公司的年头 |
| #赋值 |
| SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id; |
| SELECT DATEDIFF(CURDATE(),hire_date)/365 INTO hire_year FROM employees WHERE employee_id = emp_id; |
| #判断 |
| IF emp_sal < 8000 AND hire_year >= 5 |
| THEN UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_id; |
| END IF; |
| END // |
| DELIMITER ; |
| |
| #调用存储过程 |
| CALL update_salary_by_eid1(104); |
| |
| # 举例3:声明存储过程“update_salary_by_eid2”,定义IN参数emp_id,输入员工编号。判断该员工薪资如果低于9000元并且入职时间超过5年,就涨薪500元;否则就涨薪100元。 |
| DELIMITER // |
| CREATE PROCEDURE update_salary_by_eid2(IN emp_id INT) |
| BEGIN |
| #声明局部变量 |
| DECLARE emp_sal DOUBLE; #记录员工的工资 |
| DECLARE hire_year DOUBLE; #记录员工入职公司的年头 |
| #赋值 |
| SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id; |
| SELECT DATEDIFF(CURDATE(),hire_date)/365 INTO hire_year FROM employees WHERE employee_id = emp_id; |
| #判断 |
| IF emp_sal < 9000 AND hire_year >= 5 |
| THEN UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_id; |
| ELSE |
| UPDATE employees SET salary = salary + 100 WHERE employee_id = emp_id; |
| END IF; |
| END // |
| DELIMITER ; |
| |
| #调用 |
| CALL update_salary_by_eid2(103); |
| CALL update_salary_by_eid2(104); |
| |
| # 举例4:声明存储过程“update_salary_by_eid3”,定义IN参数emp_id,输入员工编号。 |
| # 判断该员工薪资如果低于9000元,就更新薪资为9000元;薪资如果大于等于9000元且低于10000的,但是奖金比例为NULL的,就更新奖金比例为0.01;其他的涨薪100元。 |
| DELIMITER // |
| CREATE PROCEDURE update_salary_by_eid3(IN emp_id INT) |
| BEGIN |
| #声明变量 |
| 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 < 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; |
| END // |
| DELIMITER ; |
| |
| #调用 |
| CALL update_salary_by_eid3(102); |
| CALL update_salary_by_eid3(103); |
| CALL update_salary_by_eid3(104); |
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后面不需要) |
| # 举例1:基本使用 |
| DELIMITER // |
| CREATE PROCEDURE test_case() |
| BEGIN |
| # 演示1:case ... when ...then ... |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| # 演示2:case when ... then .... |
| DECLARE var1 INT DEFAULT 10; |
| CASE |
| WHEN var1 >= 100 THEN SELECT '三位数'; |
| WHEN var1 >= 10 THEN SELECT '两位数'; |
| ELSE SELECT '个数位'; |
| END CASE; |
| END // |
| DELIMITER ; |
| |
| #调用 |
| CALL test_case(); |
| |
| # 举例2:声明存储过程“update_salary_by_eid4”,定义IN参数emp_id,输入员工编号。 |
| # 判断该员工薪资如果低于9000元,就更新薪资为9000元;薪资大于等于9000元且低于10000的,但是奖金比例为NULL的,就更新奖金比例为0.01;其他的涨薪100元。 |
| DELIMITER // |
| CREATE PROCEDURE update_salary_by_eid4(IN emp_id INT) |
| BEGIN |
| # 局部变量的声明 |
| 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; |
| CASE |
| WHEN emp_sal < 9000 THEN UPDATE employees SET salary = 9000 WHERE employee_id = emp_id; |
| WHEN 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 CASE; |
| END // |
| DELIMITER ; |
| |
| #调用 |
| CALL update_salary_by_eid4(103); |
| CALL update_salary_by_eid4(104); |
| CALL update_salary_by_eid4(105); |
| |
| # 举例3:声明存储过程update_salary_by_eid5,定义IN参数emp_id,输入员工编号。 |
| # 判断该员工的入职年限,如果是0年,薪资涨50;如果是1年,薪资涨100;如果是2年,薪资涨200;如果是3年,薪资涨300;如果是4年,薪资涨400;其他的涨薪500。 |
| DELIMITER // |
| CREATE PROCEDURE update_salary_by_eid5(IN emp_id INT) |
| BEGIN |
| #声明局部变量 |
| DECLARE hire_year INT; #记录员工入职公司的总时间(单位:年) |
| #赋值 |
| SELECT ROUND(DATEDIFF(CURDATE(),hire_date) / 365) INTO hire_year |
| FROM employees WHERE employee_id = emp_id; |
| #判断 |
| CASE hire_year |
| WHEN 0 THEN UPDATE employees SET salary = salary + 50 WHERE employee_id = emp_id; |
| WHEN 1 THEN UPDATE employees SET salary = salary + 100 WHERE employee_id = emp_id; |
| WHEN 2 THEN UPDATE employees SET salary = salary + 200 WHERE employee_id = emp_id; |
| WHEN 3 THEN UPDATE employees SET salary = salary + 300 WHERE employee_id = emp_id; |
| WHEN 4 THEN UPDATE employees SET salary = salary + 400 WHERE employee_id = emp_id; |
| ELSE UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_id; |
| END CASE; |
| END // |
| DELIMITER ; |
| |
| #调用 |
| CALL update_salary_by_eid5(101); |
LOOP
| LOOP循环语句用来重复执行某些语句。LOOP内的语句一直重复执行直到循环被退出(使用LEAVE子句),跳出循环过程 |
| |
| # 格式 |
| [loop_label:] LOOP |
| 循环执行的语句 |
| END LOOP [loop_label] |
| |
| loop_label表示LOOP语句的标注名称,该参数可以省略 |
| # 举例1: |
| DELIMITER // |
| CREATE PROCEDURE test_loop() |
| BEGIN |
| #声明局部变量 |
| DECLARE num INT DEFAULT 1; |
| loop_label:LOOP |
| # 重新赋值 |
| SET num = num + 1; |
| # 可以考虑某个代码程序反复执行 |
| IF num >= 10 THEN LEAVE loop_label; |
| END IF; |
| END LOOP loop_label; |
| # 查看num |
| SELECT num; |
| END // |
| DELIMITER ; |
| |
| #调用 |
| CALL test_loop(); |
| |
| # 举例2:当市场环境变好时,公司为了奖励大家,决定给大家涨工资。 |
| # 声明存储过程“update_salary_loop()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家涨薪,薪资涨为原来的1.1倍。直到全公司的平均薪资达到12000结束。并统计循环次数。 |
| DELIMITER // |
| CREATE PROCEDURE update_salary_loop(OUT num INT) |
| BEGIN |
| #声明变量 |
| DECLARE avg_sal DOUBLE ; #记录员工的平均工资 |
| DECLARE loop_count INT DEFAULT 0;#记录循环的次数 |
| #① 初始化条件 |
| #获取员工的平均工资 |
| SELECT AVG(salary) INTO avg_sal FROM employees; |
| loop_lab:LOOP |
| #② 循环条件 |
| #结束循环的条件 |
| IF avg_sal >= 12000 |
| THEN LEAVE loop_lab; |
| END IF; |
| #③ 循环体 |
| #如果低于12000,更新员工的工资 |
| UPDATE employees SET salary = salary * 1.1; |
| #④ 迭代条件 |
| #更新avg_sal变量的值 |
| SELECT AVG(salary) INTO avg_sal FROM employees; |
| #记录循环次数 |
| SET loop_count = loop_count + 1; |
| END LOOP loop_lab; |
| #给num赋值 |
| SET num = loop_count; |
| END // |
| DELIMITER; |
| |
| # 调用 |
| CALL update_salary_loop(@num); |
| # 查看 |
| SELECT @num; |
WHILE
| WHILE语句创建一个带条件判断的循环过程。WHILE在执行语句执行时,先对指定的表达式进行判断,如果为真,就执行循环内的语句,否则退出循环 |
| |
| |
| [while_label:] WHILE 循环条件 DO |
| 循环体 |
| END WHILE [while_label]; |
| |
| while_label为WHILE语句的标注名称;如果循环条件结果为真,WHILE语句内的语句或语句群被执行,直至循环条件为假,退出循环 |
| # 举例1: |
| DELIMITER |
| CREATE PROCEDURE test_while() |
| BEGIN |
| #初始化条件 |
| DECLARE num INT DEFAULT 1; |
| #循环条件 |
| WHILE num <= 10 DO |
| #循环体(略) |
| #迭代条件 |
| SET num = num + 1; |
| END WHILE; |
| #查询 |
| SELECT num; |
| END |
| DELIMITER ; |
| |
| #调用 |
| CALL test_while(); |
| |
| # 举例2:市场环境不好时,公司为了渡过难关,决定暂时降低大家的薪资。 |
| # 声明存储过程“update_salary_while()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家降薪,薪资降为原来的90%。直到全公司的平均薪资达到5000结束。并统计循环次数。 |
| DELIMITER |
| CREATE PROCEDURE update_salary_while(OUT num INT) |
| BEGIN |
| #声明变量 |
| DECLARE avg_sal DOUBLE ; #记录平均工资 |
| DECLARE while_count INT DEFAULT 0; #记录循环次数 |
| #赋值 |
| SELECT AVG(salary) INTO avg_sal FROM employees; |
| WHILE avg_sal > 5000 DO |
| UPDATE employees SET salary = salary * 0.9 ; |
| SET while_count = while_count + 1; |
| SELECT AVG(salary) INTO avg_sal FROM employees; |
| END WHILE; |
| #给num赋值 |
| SET num = while_count; |
| END |
| DELIMITER ; |
| |
| # 调用 |
| CALL update_salary_while(@num); |
| # 查看 |
| SELECT @num; |
REPEAT
| REPEAT语句创建一个带条件判断的循环过程。与WHILE循环不同的是,REPEAT 循环首先会执行一次循环,然后在 UNTIL 中进行表达式的判断,如果满足条件就退出,即 END REPEAT;如果条件不满足,则会就继续执行循环,直到满足退出条件为止 |
| |
| # 格式 |
| [repeat_label:] REPEAT |
| 循环体的语句 |
| UNTIL 结束循环的条件表达式 |
| END REPEAT [repeat_label] |
| |
| repeat_label为REPEAT语句的标注名称,该参数可以省略;REPEAT语句内的语句或语句群被重复,直至expr_condition为真 |
| # 举例1: |
| DELIMITER |
| CREATE PROCEDURE test_repeat() |
| BEGIN |
| #声明变量 |
| DECLARE num INT DEFAULT 1; |
| REPEAT |
| SET num = num + 1; |
| UNTIL num >= 10 |
| END REPEAT; |
| #查看 |
| SELECT num; |
| END |
| DELIMITER; |
| |
| #调用 |
| CALL test_repeat(); |
| |
| # 举例2:当市场环境变好时,公司为了奖励大家,决定给大家涨工资。 |
| # 声明存储过程“update_salary_repeat()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家涨薪,薪资涨为原来的1.15倍。直到全公司的平均薪资达到13000结束。并统计循环次数。 |
| DELIMITER |
| CREATE PROCEDURE update_salary_repeat(OUT num INT) |
| BEGIN |
| #声明变量 |
| DECLARE avg_sal DOUBLE ; #记录平均工资 |
| DECLARE repeat_count INT DEFAULT 0; #记录循环次数 |
| #赋值 |
| SELECT AVG(salary) INTO avg_sal FROM employees; |
| REPEAT |
| UPDATE employees SET salary = salary * 1.15; |
| SET repeat_count = repeat_count + 1; |
| SELECT AVG(salary) INTO avg_sal FROM employees; |
| UNTIL avg_sal >= 13000 |
| END REPEAT; |
| #给num赋值 |
| SET num = repeat_count; |
| END |
| DELIMITER ; |
| |
| # 调用 |
| CALL update_salary_repeat(@num); |
| # 查看 |
| SELECT @num; |
LEAVE
| LEAVE语句:可以用在循环语句内,或者以 BEGIN 和 END 包裹起来的程序体内,表示跳出循环或者跳出程序体的操作。如果你有面向过程的编程语言的使用经验,你可以把 LEAVE 理解为 break |
| |
| |
| LEAVE 标记名 |
| |
| label参数表示循环的标志。LEAVE和BEGIN ... END或循环一起被使用 |
| # 举例1:创建存储过程 “leave_begin()”,声明INT类型的IN参数num。给BEGIN...END加标记名,并在BEGIN...END中使用IF语句判断num参数的值。 |
| 如果num<=0,则使用LEAVE语句退出BEGIN...END; |
| 如果num=1,则查询“employees”表的平均薪资; |
| 如果num=2,则查询“employees”表的最低薪资; |
| 如果num>2,则查询“employees”表的最高薪资。 |
| IF语句结束后查询“employees”表的总人数 |
| */ |
| 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 // |
| DELIMITER ; |
| |
| #调用 |
| CALL leave_begin(1); |
| |
| # 举例2:当市场环境不好时,公司为了渡过难关,决定暂时降低大家的薪资。 |
| # 声明存储过程“leave_while()”,声明OUT参数num,输出循环次数,存储过程中使用WHILE循环给大家降低薪资为原来薪资的90%,直到全公司的平均薪资小于等于10000,并统计循环次数。 |
| DELIMITER // |
| CREATE PROCEDURE leave_while(OUT num INT) |
| BEGIN |
| DECLARE avg_sal DOUBLE;#记录平均工资 |
| DECLARE while_count INT DEFAULT 0; #记录循环次数 |
| SELECT AVG(salary) INTO avg_sal FROM employees; # 初始化条件 |
| while_label:WHILE TRUE DO # 循环条件 |
| # 循环体 |
| IF avg_sal <= 10000 THEN |
| LEAVE while_label; |
| END IF; |
| UPDATE employees SET salary = salary * 0.9; |
| SET while_count = while_count + 1; |
| # 迭代条件 |
| SELECT AVG(salary) INTO avg_sal FROM employees; |
| END WHILE; |
| # 赋值 |
| SET num = while_count; |
| END // |
| DELIMITER ; |
| |
| # 调用 |
| CALL leave_while(@num); |
| # 查看 |
| SELECT @num; |
ITERATE
| ITERATE语句:只能用在循环语句(LOOP、REPEAT和WHILE语句)内,表示重新开始循环,将执行顺序转到语句段开头处。如果你有面向过程的编程语言的使用经验,你可以把 ITERATE 理解为 continue,意思为“再次循环” |
| |
| # 格式 |
| ITERATE label |
| |
| label参数表示循环的标志。ITERATE语句必须跟在循环标志前面 |
| |
| |
| |
| |
| |
| DELIMITER // |
| CREATE PROCEDURE test_iterate() |
| BEGIN |
| DECLARE num INT DEFAULT 0; |
| loop_label:LOOP |
| #赋值 |
| SET num = num + 1; |
| IF num < 10 |
| THEN ITERATE loop_label; |
| ELSEIF num > 15 |
| THEN LEAVE loop_label; |
| END IF; |
| SELECT '十年人间'; |
| END LOOP; |
| END // |
| DELIMITER ; |
| |
| # 调用 |
| CALL test_iterate(); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下