系统变量分为全局系统变量(需要添加 global 关键字)以及会话系统变量(需要添加 session 关键字),有时也把全局系统变量简称为全局变量,有时也把会话系统变量称为local变量。如果不写,默认会话级别。静态变量(在 MySQL 服务实例运行期间它们的值不能使用 set 动态修改)属于特殊的全局系统变量。
#方式2:使用局部变量 DELIMITER // CREATEPROCEDURE add_value() BEGIN #局部变量 DECLARE m INTDEFAULT1; DECLARE n INTDEFAULT3; DECLARE SUM INT; SET SUM = m+n; SELECT SUM; END// DELIMITER ; 12345678910111213141516171819
#1.7 局部变量 /* 1、局部变量必须满足: ① 使用DECLARE声明 ② 声明并使用在BEGIN ... END 中 (使用在存储过程、函数中) ③ DECLARE的方式声明的局部变量必须声明在BEGIN中的首行的位置。 2、声明格式: DECLARE 变量名 类型 [default 值]; # 如果没有DEFAULT子句,初始值为NULL 3、赋值: 方式1: SET 变量名=值; SET 变量名:=值; 方式2: SELECT 字段名或表达式 INTO 变量名 FROM 表; 4、使用 SELECT 局部变量名; */
#举例: DELIMITER // CREATEPROCEDURE test_var() BEGIN #1、声明局部变量 DECLARE a INTDEFAULT0; DECLARE b INT ; #DECLARE a,b INTDEFAULT0; DECLARE emp_name VARCHAR(25); #2、赋值 SET a =1; SET b :=2; SELECT last_name INTO emp_name FROM employees WHERE employee_id =101; #3、使用 SELECT a,b,emp_name; END// DELIMITER ;
#调用存储过程 CALL test_var(); /*输出: +------+------+----------+ | a | b | emp_name | +------+------+----------+ | 1 | 2 | Kochhar | +------+------+----------+ */ #举例1:声明局部变量,并分别赋值为employees表中employee_id为102的last_name和salary DELIMITER // CREATEPROCEDURE test_pro() BEGIN #声明 DECLARE emp_name VARCHAR(25); DECLARE sal DOUBLE(10,2) DEFAULT0.0; #赋值 SELECT last_name,salary INTO emp_name,sal FROM employees WHERE employee_id =102; #使用 SELECT emp_name,sal; END// DELIMITER ;
#调用存储过程 CALL test_pro(); /* +----------+----------+ | emp_name | sal | +----------+----------+ | De Haan | 17000.00 | +----------+----------+ */ SELECT last_name,salary FROM employees WHERE employee_id =102;
ELSE UPDATE employees SET salary = salary +100WHERE employee_id = emp_id; END IF;
END// DELIMITER ; 1234567891011121314151617181920
3.2 分支结构之 CASE
CASE 语句的语法结构1:
sql
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#情况一:类似于switch CASE 表达式 WHEN 值1THEN 结果1或语句1(如果是语句,需要加分号) WHEN 值2THEN 结果2或语句2(如果是语句,需要加分号) ... ELSE 结果n或语句n(如果是语句,需要加分号) END [case](如果是放在beginend中需要加上case,如果放在select后面不需要) CASE 语句的语法结构2:
#情况二:类似于多重if CASE WHEN 条件1THEN 结果1或语句1(如果是语句,需要加分号) WHEN 条件2THEN 结果2或语句2(如果是语句,需要加分号) ... ELSE 结果n或语句n(如果是语句,需要加分号) END [case](如果是放在beginend中需要加上case,如果放在select后面不需要) 1234567891011121314151617
举例1: 使用CASE流程控制语句的第1种格式,判断val值等于1、等于2,或者两者都不等。
sql
1 2 3 4 5 6
CASE val WHEN1THENSELECT'val is 1'; WHEN2THENSELECT'val is 2'; ELSESELECT'val is not 1 or 2'; ENDCASE; 12345
举例2: 使用CASE流程控制语句的第2种格式,判断val是否为空、小于0、大于0或者等于0。
sql
1 2 3 4 5 6 7
CASE WHEN val ISNULLTHENSELECT'val is null'; WHEN val <0THENSELECT'val is less than 0'; WHEN val >0THENSELECT'val is greater than 0'; ELSESELECT'val is 0'; ENDCASE; 123456
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 THENUPDATE employees SET salary=9000WHERE employee_id = emp_id; WHEN emp_sal<10000AND bonus ISNULL THENUPDATE employees SET commission_pct=0.01WHERE employee_id = emp_id;
ELSE UPDATE employees SET salary=salary+100WHERE employee_id = emp_id;
DELIMITER // CREATEPROCEDURE update_salary_loop(OUT num INT)
BEGIN DECLARE avg_salary DOUBLE; DECLARE loop_count INTDEFAULT0;
SELECTAVG(salary) INTO avg_salary FROM employees;
label_loop:LOOP IF avg_salary >=12000THEN LEAVE label_loop; END IF; UPDATE employees SET salary = salary *1.1; SET loop_count = loop_count +1; SELECTAVG(salary) INTO avg_salary FROM employees; END LOOP label_loop; SET num = loop_count; END// DELIMITER ; 12345678910111213141516171819
DELIMITER // CREATEPROCEDURE test_while() BEGIN DECLARE i INTDEFAULT0; WHILE i <10 DO SET i = i +1; END WHILE; SELECT i; END// DELIMITER ; 12345678910 #调用 CALL test_while(); 12
DELIMITER // CREATEPROCEDURE update_salary_repeat(OUT num INT) BEGIN DECLARE avg_sal DOUBLE ; DECLARE repeat_count INTDEFAULT0; SELECTAVG(salary) INTO avg_sal FROM employees;
REPEAT UPDATE employees SET salary = salary *1.15; SET repeat_count = repeat_count +1;
CREATEPROCEDURE leave_begin(IN num INT) begin_label: BEGIN IF num<=0 THEN LEAVE begin_label; ELSEIF num=1 THENSELECTAVG(salary) FROM employees; ELSEIF num=2 THENSELECTMIN(salary) FROM employees; ELSE SELECTMAX(salary) FROM employees; END IF; SELECTCOUNT(*) FROM employees; END// DELIMITER ; 12345678910111213141516
CREATEPROCEDURE test_iterate() BEGIN DECLARE num INTDEFAULT0; my_loop:LOOP SET num = num +1; IF num <10 THEN ITERATE my_loop; ELSEIF num >15 THEN LEAVE my_loop; END IF; SELECT'尚硅谷:让天下没有难学的技术'; END LOOP my_loop; END// DELIMITER ; 12345678910111213141516
SELECT* FROM employees WHERE employee_id IN (102,103,104);
##3.2 分支结构之case #举例1:基本使用 DELIMITER // CREATEPROCEDURE test_case() BEGIN #演示1:case ... when ...then ... /* declare var int default 2; 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; */ #演示2:casewhen ... then .... DECLARE var1 INTDEFAULT10; CASE WHEN var1 >=100THENSELECT'三位数'; WHEN var1 >=10THENSELECT'两位数'; ELSESELECT'个数位'; ENDCASE;
DELIMITER // CREATEPROCEDURE 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 WHEN0THENUPDATE employees SET salary = salary +50WHERE employee_id = emp_id; WHEN1THENUPDATE employees SET salary = salary +100WHERE employee_id = emp_id; WHEN2THENUPDATE employees SET salary = salary +200WHERE employee_id = emp_id; WHEN3THENUPDATE employees SET salary = salary +300WHERE employee_id = emp_id; WHEN4THENUPDATE employees SET salary = salary +400WHERE employee_id = emp_id; ELSEUPDATE employees SET salary = salary +500WHERE employee_id = emp_id; ENDCASE; END// DELIMITER ;
#调用 CALL update_salary_by_eid5(101);
SELECT* FROM employees
DROPPROCEDURE update_salary_by_eid5;
#4.1 循环结构之LOOP /* [loop_label:] LOOP 循环执行的语句 END LOOP [loop_label] */ #举例1: DELIMITER // CREATEPROCEDURE test_loop() BEGIN #声明局部变量 DECLARE num INTDEFAULT1; loop_label:LOOP #重新赋值 SET num = num +1; #可以考虑某个代码程序反复执行。(略) IF num >=10THEN LEAVE loop_label; END IF; END LOOP loop_label; #查看num SELECT num;
#举例2:当市场环境变好时,公司为了奖励大家,决定给大家涨工资。 #声明存储过程“update_salary_loop()”,声明OUT参数num,输出循环次数。 #存储过程中实现循环给大家涨薪,薪资涨为原来的1.1倍。直到全公司的平 #均薪资达到12000结束。并统计循环次数。 DELIMITER // CREATEPROCEDURE update_salary_loop(OUT num INT) BEGIN #声明变量 DECLARE avg_sal DOUBLE ; #记录员工的平均工资 DECLARE loop_count INTDEFAULT0;#记录循环的次数 #① 初始化条件 #获取员工的平均工资 SELECTAVG(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变量的值 SELECTAVG(salary) INTO avg_sal FROM employees; #记录循环次数 SET loop_count = loop_count +1; END LOOP loop_lab; #给num赋值 SET num = loop_count;
END// DELIMITER ;
SELECTAVG(salary) FROM employees;
CALL update_salary_loop(@num); SELECT@num;
#4.2 循环结构之WHILE /* [while_label:] WHILE 循环条件 DO 循环体 END WHILE [while_label]; */ #举例1: DELIMITER // CREATEPROCEDURE test_while() BEGIN #初始化条件 DECLARE num INTDEFAULT1; #循环条件 WHILE num <=10 DO #循环体(略) #迭代条件 SET num = num +1; END WHILE; #查询 SELECT num;
DELIMITER // CREATEPROCEDURE update_salary_while(OUT num INT) BEGIN #声明变量 DECLARE avg_sal DOUBLE ; #记录平均工资 DECLARE while_count INTDEFAULT0; #记录循环次数 #赋值 SELECTAVG(salary) INTO avg_sal FROM employees; WHILE avg_sal >5000 DO UPDATE employees SET salary = salary *0.9 ; SET while_count = while_count +1; SELECTAVG(salary) INTO avg_sal FROM employees; END WHILE; #给num赋值 SET num = while_count; END// DELIMITER ;
#调用 CALL update_salary_while(@num);
SELECT@num;
SELECTAVG(salary) FROM employees;
#4.3 循环结构之REPEAT /* [repeat_label:] REPEAT 循环体的语句 UNTIL 结束循环的条件表达式 END REPEAT [repeat_label] */
#举例1: DELIMITER // CREATEPROCEDURE test_repeat() BEGIN #声明变量 DECLARE num INTDEFAULT1; 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 // CREATEPROCEDURE update_salary_repeat(OUT num INT)
BEGIN #声明变量 DECLARE avg_sal DOUBLE ; #记录平均工资 DECLARE repeat_count INTDEFAULT0; #记录循环次数 #赋值 SELECTAVG(salary) INTO avg_sal FROM employees; REPEAT UPDATE employees SET salary = salary *1.15; SET repeat_count = repeat_count +1; SELECTAVG(salary) INTO avg_sal FROM employees; UNTIL avg_sal >=13000 END REPEAT; #给num赋值 SET num = repeat_count;
#5.1 LEAVE的使用 /* **举例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 // CREATEPROCEDURE leave_begin(IN num INT) begin_label:BEGIN IF num <=0 THEN LEAVE begin_label; ELSEIF num =1 THENSELECTAVG(salary) FROM employees; ELSEIF num =2 THENSELECTMIN(salary) FROM employees; ELSE SELECTMAX(salary) FROM employees; END IF; #查询总人数 SELECTCOUNT(*) FROM employees;
END// DELIMITER ;
#调用 CALL leave_begin(1);
#举例2:当市场环境不好时,公司为了渡过难关,决定暂时降低大家的薪资。 #声明存储过程“leave_while()”,声明OUT参数num,输出循环次数,存储过程中使用WHILE #循环给大家降低薪资为原来薪资的90%,直到全公司的平均薪资小于等于10000,并统计循环次数。 DELIMITER // CREATEPROCEDURE leave_while(OUT num INT)
BEGIN # DECLARE avg_sal DOUBLE;#记录平均工资 DECLARE while_count INTDEFAULT0; #记录循环次数 SELECTAVG(salary) INTO avg_sal FROM employees; #① 初始化条件 while_label:WHILE TRUE DO #② 循环条件 #③ 循环体 IF avg_sal <=10000THEN LEAVE while_label; END IF; UPDATE employees SET salary = salary *0.9; SET while_count = while_count +1; #④ 迭代条件 SELECTAVG(salary) INTO avg_sal FROM employees; END WHILE; #赋值 SET num = while_count;
BEGIN DECLARE num INTDEFAULT0; 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(); /* +------------------------+ | :让天下没有难学的技术 | +------------------------+ | 让天下没有难学的技术 | +------------------------+ 1 row in set (0.00 sec) +------------------------+ | :让天下没有难学的技术 | +------------------------+ | 让天下没有难学的技术 | +------------------------+ 1 row in set (0.00 sec) +------------------------+ | :让天下没有难学的技术 | +------------------------+ | 让天下没有难学的技术 | +------------------------+ 1 row in set (0.01 sec) +------------------------+ | :让天下没有难学的技术 | +------------------------+ | 让天下没有难学的技术 | +------------------------+ 1 row in set (0.01 sec) +------------------------+ | :让天下没有难学的技术 | +------------------------+ | 让天下没有难学的技术 | +------------------------+ 1 row in set (0.02 sec) +------------------------+ | :让天下没有难学的技术 | +------------------------+ | 让天下没有难学的技术 | +------------------------+ */
BEGIN DECLARE avg_sal DOUBLE; SELECTAVG(salary) INTO avg_sal FROM employees e JOIN departments d ON e.department_id = d.department_id WHERE d.department_name = dept_name; RETURN avg_sal;
BEGIN IF sal <3000 THENDELETEFROM employees WHERE salary = sal; ELSEIF sal <=5000 THENUPDATE employees SET salary = salary +1000WHERE salary = sal; ELSE UPDATE employees SET salary = salary +500WHERE salary = sal; END IF;
END $
DELIMITER ;
#调用 CALL test_if_pro(24000);
SELECT*FROM employees;
#3. 创建存储过程insert_data(),传入参数为 IN 的 INT 类型变量 insert_count,实现向admin表中 #批量插入insert_count条记录
CREATE TABLE admin( id INTPRIMARY KEY AUTO_INCREMENT, user_name VARCHAR(25) NOT NULL, user_pwd VARCHAR(35) NOT NULL );
SELECT*FROM admin;
DELIMITER $
CREATEPROCEDURE insert_data(IN insert_count INT)
BEGIN #声明变量 DECLARE init_count INTDEFAULT1; #①初始化条件 WHILE init_count <= insert_count DO #② 循环条件 #③ 循环体 INSERT INTO admin(user_name,user_pwd) VALUES (CONCAT('atguigu-',init_count),ROUND(RAND()*1000000)); #④ 迭代条件 SET init_count = init_count +1; END WHILE;
END $
DELIMITER ;
#调用 CALL insert_data(100);
#3. 游标的使用
#创建存储过程update_salary(),参数1为 IN 的INT型变量dept_id,表示部门id; #参数2为 IN的INT型变量change_sal_count,表示要调整薪资的员工个数。查询指定id部门的员工信息, #按照salary升序排列,根据hire_date的情况,调整前change_sal_count个员工的薪资,详情如下。
DELIMITER $
CREATEPROCEDURE update_salary(IN dept_id INT,IN change_sal_count INT) BEGIN #声明变量 DECLARE emp_id INT ;#记录员工id DECLARE emp_hire_date DATE; #记录员工入职时间 DECLARE init_count INTDEFAULT1; #用于表示循环结构的初始化条件 DECLARE add_sal_rate DOUBLE ; #记录涨薪的比例 #声明游标 DECLARE emp_cursor CURSORFORSELECT employee_id,hire_date FROM employees WHERE department_id = dept_id ORDERBY salary ASC; #打开游标 OPEN emp_cursor; WHILE init_count <= change_sal_count DO
#使用游标 FETCH emp_cursor INTO emp_id,emp_hire_date; #获取涨薪的比例 IF (YEAR(emp_hire_date) <1995) THENSET add_sal_rate =1.2; ELSEIF(YEAR(emp_hire_date) <=1998) THENSET add_sal_rate =1.15; ELSEIF(YEAR(emp_hire_date) <=2001) THENSET add_sal_rate =1.10; ELSE SET add_sal_rate =1.05; END IF; #涨薪操作 UPDATE employees SET salary = salary * add_sal_rate WHERE employee_id = emp_id; #迭代条件的更新 SET init_count = init_count +1; END WHILE; #关闭游标 CLOSE emp_cursor;
END $
DELIMITER ;
#调用 CALL update_salary(50,3);
SELECT employee_id,hire_date,salary FROM employees WHERE department_id =50 ORDERBY salary ASC;