【⑰MySQL】 variable | loop | cursor | handler

foreword

✨Welcome to Xiao K 's MySQL column , this section will bring you the sharing of MySQL variables | loops | cursors | handlers


1. Variables

In the stored procedures and functions of the MySQL database, variables can be used to store the intermediate result data of the query or calculation, or to output the final result data.

In the MySQL database, variables are divided into 系统变量and 用户自定义变量.

1.1 System variables

1.1.1 Classification of system variables

Variables are defined by the system, not by the user, and belong to the server level. When starting the MySQL service and generating the MySQL service instance, MySQL will assign values ​​to the system variables in the memory of the MySQL server, and these system variables define the attributes and characteristics of the current MySQL service instance. The values ​​of these system variables are either the default values ​​of the parameters when compiling MySQL, or the parameter values ​​in configuration files (such as my.ini, etc.). You can view the system variables of the MySQL documentation in the official website Server System Variables .

System variables are divided into global system variables ( globalkeywords need to be added) and session system variables ( sessionkeywords need to be added). Sometimes global system variables are referred to as global variables for short, and session system variables are sometimes called local variables. ** If not specified, the default is session level. **Static variables (their values ​​cannot be dynamically modified using set during the running of the MySQL service instance) are special global system variables.

After each MySQL client successfully connects to the MySQL server, a corresponding session will be generated. During a session, the MySQL service instance will generate session system variables corresponding to the session in the memory of the MySQL server. The initial values ​​of these session system variables are copies of the global system variable values. As shown below:

insert image description here

  • Global system variables are valid for all sessions (connections), but not across restarts.
  • Session system variables are valid only for the current session (connection). During the session, the modification of the value of a session system variable by the current session will not affect the value of the same session system variable in other sessions.
  • A modification of the value of a global system variable in session 1 will result in a modification of the value of the same global system variable in session 2.

Some system variables in MySQL can only be global, such as max_connections is used to limit the maximum number of connections of the server; some system variable scope can be both global and session, such as character_set_client is used to set the character set of the client; some system variables The scope of can only be the current session, for example, pseudo_thread_id is used to mark the MySQL connection ID of the current session.

1.1.2 View system variables

  • View all or some system variables

    #查看所有全局变量
    SHOW GLOBAL VARIABLES;
    
    #查看所有会话变量
    SHOW SESSION VARIABLES;
    #或
    SHOW VARIABLES;
    
    #查看满足条件得部分系统变量
    SHOW GLOBAL VARIABLES LIKE '%标识符%';
    
    #查看满足条件的部分会话变量
    SHOW SESSION VARIABLES LIKE '%标识符%'
    

    example:

    SHOW GLOBAL VARIABLES LIKE 'admin_%';
    
  • View specified system variables

As a MySQL coding standard, system variables in MySQL begin with two "@", among which "@@global" is only used to mark global system variables, and "@@session" is only used to mark session system variables. "@@" first marks the session system variable, if the session system variable does not exist, then marks the global system variable.

#查看指定的系统变量的值
SELECT @@global.变量名;

#查看指定的会话变量的值
SELECT @@session.变量名;
#或
SELECT @@变量名;
  • Modify the value of a system variable

Sometimes, the database administrator needs to modify the default value of the system variable in order to modify the properties and characteristics of the current session or MySQL service instance. specific method:

Method 1: Modify the MySQL configuration file, and then modify the value of the MySQL system variable (this method requires restarting the MySQL service)

Method 2: Use the "set" command to reset the value of the system variable while the MySQL service is running

#为某个系统变量赋值
#方式1:
SET @@global.变量名=值;
#方式2:
SET GLOBAL 变量名=值;

#为某个会话变量赋值
#方式1:
SET @@session.变量名=值;
#方式2:
SET SESSION 变量名=值

example:

SELECT @@global.autocommit;
SET GLOBAL autocommit=0;
SELECT @@session.use_secondary_engine;
SET @@session.use_secondary_engine='OFF';
SET GLOBAL max_connections = 1000;
SELECT @@global.max_connections;

1.1.3 Supplement: New feature of MySQL 8.0 - Persistence of global variables

In the MySQL database, global variables can be set through the SET GLOBAL statement. For example, setting the server statement timeout limit can be achieved by setting the system variable max_execution_time:

SET GLOBAL MAX_EXECUTION_TIME=2000;

Variable values ​​set using the SET GLOBAL statement take effect only temporarily. After the database restarts, the server will read the default values ​​of the variables from the MySQL configuration file. MySQL version 8.0 adds the SET PERSIST command. For example, to set the server's maximum number of connections to 1000:

SET PERSIST global max_connections = 1000;

MySQL will save the configuration of this command to the mysqld-auto.cnf file in the data directory, and it will read this file at the next startup, and use the configuration in it to overwrite the default configuration file.

Example:

View the value of the global variable max_connections, the results are as follows:

mysql> show variables like '%max_connections%';
+------------------------+-------+
| Variable_name	| Value  |
+------------------------+-------+
| max_connections	| 151  |
| mysqlx_max_connections | 100|
+------------------------+-------+
2 rows in set, 1 warning (0.00 sec)

Set the value of the global variable max_connections:

mysql> set persist max_connections=1000; 
Query OK, 0 rows affected (0.00 sec)

重启MySQL服务器 , query the value of max_connections again:

mysql> show variables like '%max_connections%';
+------------------------+-------+
| Variable_name	| Value |
+------------------------+-------+
| max_connections	| 1000 |
| mysqlx_max_connections | 100	|
+------------------------+-------+
2 rows in set, 1 warning (0.00 sec)

1.2 User variables

1.2.1 Classification of user variables

User variables are defined by users themselves. As the MySQL coding standard, user variables in MySQL start with a "@". According to the different scope of action, it is divided into 会话用户变量and 局部变量.

  • Session user variables: the scope is the same as session variables, only valid for the current connection session.
  • Local variables: valid only in BEGIN and END statement blocks. Local variables can only be used in stored procedures and functions.

Note: It is case-sensitive in versions before MySQL 5.0, so pay attention (it is not case-sensitive after MySQL 5.0).

1.2.2 Session User Variables

  • variable definition
#方式1:"= 或 ":=
SET @用户变量=值
SET @用户变量:=值

#方式2:":=" 或 INTO关键字
SELECT @用户变量 :=表达式[FROM等子句];
SELECT 表达式 INTO @用户变量 [FROM等子句];
  • View the value of a custom variable
SELECT @用户变量;

example:

SET @n1 =1;
SET @n2 :=3;
SET @sum := @n1+@n2;
SELECT @sum;
SELECT @num := COUNT(*) FROM emps;
SELECT @num;
SELECT AVG(sal) INTO @avgsal FROM emps;
SELECT  @avgsal;
#查看某个未定义的变量时,将得到NULL值
SELECT @maye;

1.2.3 Local variables

Definition: You can use the DECLARE statement to define a local variable scope: it is only valid in the BEGIN ... END where it is defined

Position: can only be placed in BEGIN ... END, and only in the first sentence

BEGIN
	#声明局部变量
	DECLARE 变量1 数据类型 [DEFAULT 默认值];
	DECLARE 变量2,变量3,... 数据类型 [DEFAULT 默认值];
	
	#为局部变量赋值
	SET 变量1 = 值;
	SELECT 字段 INTO 变量2 [FROM 子句];
	
	#查看局部变量的值
	SELECT 变量1,变量2,变量3;
END	

1. Define variables

DECLARE 变量名 类型 [DEFAULT 值]; # 如果没有DEFAULT子句,初始值为NULL

example:

DECLARE num INT DEFAULT 100;

2. Variable assignment

Method 1: Generally used to assign simple values

SET 变量=值;
SET 变量:=值;

Method 2: Generally used to assign field values ​​in tables

SELECT 字段名或表达式 INTO 变量名 FROM 表;

3. Using variables

SELECT 局部变量名;

Example 1 : Declare local variables and assign them to ename and sal with empno 7369 in the emps table.

CREATE PROCEDURE set_value() 
BEGIN
	DECLARE emp_name VARCHAR(25); 
	DECLARE em_sal DOUBLE(10,2);

	SELECT ename,sal INTO emp_name,emp_sal 
	FROM emps
	WHERE empno = 7369;

	SELECT emp_name,emp_sal; 
END;

Example 2 : Declare two variables, sum and print (using session user variables and local variables respectively)

#方式1:使用用户变量
SET @m=1;
SET @n=2;
SET @sum = @m+@n;
SELECT @sum;
#方式2:使用局部变量
CREATE PROCEDURE add_value()
BEGIN
	DECLARE m INT DEFAULT 1;
	DECLARE n INT DEFAULT 3;
	DECLARE sum INT;
	
	SET sum=m+n;
	SELECT sum;
END;

Example 3 : Create a stored procedure "diff_sal" to query the salary gap between an employee and his leader, use the IN parameter eno to receive the employee number, and use the OUT parameter dif_sal to output the salary gap result.

CREATE PROCEDURE diff_sal(IN eno INT,OUT dif_sal DOUBLE)
BEGIN
	DECLARE mgr_eno INT;
	DECLARE mgr_sal DOUBLE(10,2);
	DECLARE eno_sal DOUBLE(10,2);
	SELECT sal,mgr INTO eno_sal,mgr_eno FROM emp WHERE empno=eno;
	SELECT sal INTO mgr_sal FROM emp WHERE empno=mgr_eno;
	SET dif_sal=mgr_sal-eno_sal;
END;
CALL diff_sal(7566,@dif_sal);
SELECT @dif_sal;

1.2.4 Comparison between session user variables and local variables

variable type scope define location grammar
session user variable scope current session anywhere a location session is defined Add the @ symbol to the syntax without specifying the type
local variable Define it in the BEGIN END First sentence of BEGIN END Generally, you don’t need to add @, you need to specify the type

2. Define conditions and handlers

The definition condition is to define in advance the problems that may be encountered during the execution of the program, and the handler defines the processing methods that should be adopted when encountering problems, and ensures that the stored procedure or function can continue to execute when encountering warnings or errors. In this way, the ability of the stored program to deal with problems can be enhanced, and the abnormal stop of the program can be avoided.

Note: Definition conditions and handlers are supported in stored procedures and stored functions.

2.1 Case Analysis

Case Study : Create a stored procedure named "UpdateData". code show as below:

CREATE PROCEDURE UpdateData() 
BEGIN
	SET @x = 1;
	UPDATE emps SET sal = NULL WHERE ename = 'WARD'; 
	SET @x = 2;
	UPDATE emps SET sal = 200 WHERE ename = 'WARD'; 
	SET @x = 3;
END ;

Call the stored procedure:

mysql> CALL UpdateData();
ERROR 1048 (23000): Column 'sal' cannot be null

mysql> SELECT @x;
+------+
| @x	|
+------+
|	1 |
+------+
1 row in set (0.00 sec)

It can be seen that the value of the @x variable is 1 at this time. Combined with the code of the SQL statement for creating the stored procedure, it can be concluded that the conditions and processing procedures are not defined in the stored procedure, and when the SQL statement executed in the stored procedure reports an error, the MySQL database will throw an error and exit the current SQL logic, no longer Continue down.

2.2 Define conditions

Defining conditions is to name the error codes in MySQL, which helps to make the stored program code clearer. It associates an error name with an error condition. This name can then be used in the DECLARE HANDLER statement that defines the handler.

Define conditions using the DECLARE statement, the syntax is as follows:

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

Description of the error code:

  • MySQL_error_codeBoth sqlstate_valuecan indicate a MySQL error.

    • MySQL_error_code is a numeric error code.
    • sqlstate_value is an error code of string type with a length of 5.
  • For example, in ERROR 1048 (23000), 1048 is MySQL_error_code and '23000' is sqlstate_value.

  • For example, in ERROR 1146 (42S02), 1146 is MySQL_error_code and '42S02' is sqlstate_value.

Example 1 : Define the "Field_Not_Be_NULL" error name to correspond to the error type "ERROR 1048 (23000)" that violates the non-null constraint in MySQL.

#使用MySQL_error_code
DECLARE Field_Not_Be_NULL CONDITION FOR 1048;

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

Example 2 : Define the "ERROR 1148 (42000)" error with the name command_not_allowed.

#使用MySQL_error_code
DECLARE command_not_allowed CONDITION FOR 1148;

#使用sqlstate_value
DECLARE command_not_allowed CONDITION FOR SQLSTATE '42000';

2.3 Define handlers

Special handlers can be defined for certain types of errors that occur during SQL execution. When defining a handler, the syntax for using the DECLARE statement is as follows:

DECLARE 处理方式 HANDLER FOR 错误类型 处理语句;
  • Processing method : The processing method has 3 values: CONTINUE, EXIT, UNDO.

    • CONTINUE: Indicates that the error will not be processed and the execution will continue.
    • EXIT: Indicates to exit immediately when encountering an error.
    • UNDO: Indicates that the previous operation is undone after encountering an error. Such operations are not currently supported in MySQL.
  • Error type: (i.e. condition) can have the following values:

    • SQLSTATE '字符串错误码': Indicates the error code of the sqlstate_value type with a length of 5;
    • MySQL_error_code: Matching numeric type error code;
    • 错误名称: Indicates the name of the error condition defined by DECLARE ... CONDITION.
    • SQLWARNING: Match all SQLSTATE error codes starting with 01;
    • NOT FOUND: Match all SQLSTATE error codes starting with 02;
    • SQLEXCEPTION: Match all SQLSTATE error codes that are not caught by SQLWARNING or NOT FOUND;

Processing statement: : If one of the above conditions occurs, use the corresponding processing method and execute the specified processing statement. Statements can be as simple as "SET variable = value" or compound statements written using BEGIN ... END.

There are several ways to define handlers, the code is as follows:

#方法1:捕获sqlstate_value
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info = 'NO_SUCH_TABLE';

#方法2:捕获mysql_error_value
DECLARE CONTINUE HANDLER FOR 1146 SET @info = 'NO_SUCH_TABLE';

#方法3:先定义条件,再调用
DECLARE no_such_table CONDITION FOR 1146;
DECLARE CONTINUE HANDLER FOR NO_SUCH_TABLE SET @info = 'NO_SUCH_TABLE';

#方法4:使用SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING SET @info = 'ERROR';

#方法5:使用NOT FOUND
DECLARE EXIT HANDLER FOR NOT FOUND SET @info = 'NO_SUCH_TABLE';

#方法6:使用SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info = 'ERROR';

2.4 Case Resolution

In the stored procedure, define a handler, capture the sqlstate_value value, and execute when the MySQL_error_code value is 1048

CONTINUE operation, and set the value of @proc_value to -1.

CREATE PROCEDURE UpdateDataNoCondition() 
BEGIN
	#定义处理程序
	DECLARE CONTINUE HANDLER FOR 1048 SET @proc_value = -1;

	SET @x = 1;
	UPDATE emps SET sal = NULL WHERE ename = 'WARD'; 
	SET @x = 2;
	UPDATE emps SET sal = 200 WHERE ename = 'WARD'; 
	SET @x = 3;
END ;

Call process:

mysql> CALL UpdateDataWithCondition(); Query OK, 0 rows affected (0.01 sec)

mysql> SELECT @x,@proc_value;
+------+-------------+
| @x	| @proc_value |
+------+-------------+
|	3 |	-1 |
+------+-------------+
1 row in set (0.00 sec)

Example : Create a stored procedure named "InsertDataWithCondition", the code is as follows.

In the stored procedure, define a handler, capture the value of sqlstate_value, execute the EXIT operation when the value of sqlstate_value is 23000, and set the value of @proc_value to -1.

#准备工作
CREATE TABLE depts 
AS
SELECT * FROM test.dept;

ALTER TABLE depts
ADD CONSTRAINT uk_dept_name UNIQUE(deptno);
CREATE PROCEDURE InsertDataWithCondition() 
BEGIN
	DECLARE duplicate_entry CONDITION FOR SQLSTATE '23000' ; 
	DECLARE EXIT HANDLER FOR duplicate_entry SET @proc_value = -1;

	SET @x = 1;
	INSERT INTO depts(dname) VALUES('测试'); 
	SET @x = 2;
	INSERT INTO depts(dname) VALUES('测试');
	SET @x = 3;
END ;

Call the stored procedure:

mysql> CALL InsertDataWithCondition(); Query OK, 0 rows affected (0.01 sec)

mysql> SELECT @x,@proc_value;
+------+-------------+
| @x	| @proc_value |
+------+-------------+
|	2 |	-1 |
+------+-------------+
1 row in set (0.00 sec)

3. Process control

It is impossible to solve complex problems through one SQL statement, we need to perform multiple SQL operations. The role of the flow control statement is to control the execution order of the SQL statements in the stored procedure, which is an essential part of our complex operations. As long as the program is executed, the process can be divided into three categories:

  • Sequential structure: the program is executed sequentially from top to bottom
  • Branch structure: the program is selected and executed according to the conditions, and one of the two or more paths is selected for execution
  • Loop structure: When the program meets certain conditions, a set of statements is executed repeatedly

There are three main types of flow control statements for MySQL. Note: Can only be used for stored programs.

  • Conditional judgment statement: IF statement and CASE statement
  • Looping Statements: LOOP, WHILE, and REPEAT Statements
  • Jump statements: ITERATE and LEAVE statements

3.1 Branch structure

3.1.1 IF of branch structure

The syntax structure of the IF statement is:

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

Executes the corresponding statement depending on whether the expression evaluates to TRUE or FALSE. Here the content in "[]" is optional.

  • Features: ① Different expressions correspond to different operations

                 ② 使用在begin end中
    
  • Example 1:

IF val IS NULL
THEN SELECT 'val is null';
ELSE SELECT 'val is not null';	
END IF

Example 2 : Declare the stored procedure "update_sal_by_eno", define the IN parameter eno, and enter the employee number. It is judged that if the salary of the employee is less than 2,000 yuan and the employee has been employed for more than 5 years, the salary will be increased by 500 yuan; otherwise, it will remain unchanged.

CREATE PROCEDURE update_sal_by_eno(IN eno INT)
BEGIN
	DECLARE emp_sal DOUBLE;
	DECLARE emp_hir DOUBLE;
	SELECT sal,DATEDIFF(CURDATE(),hiredate)/365 INTO emp_sal,emp_hir 
	FROM emp WHERE empno=eno;
	IF emp_sal<2000 AND emp_hir > 5
	THEN UPDATE emp SET sal=sal+500 WHERE empno=eno;
	END IF;
END;
CALL update_sal_by_eno(7369);
SELECT * FROM emp WHERE empno=7369;

Example 3 : Declare the stored procedure "update_sal_by_eno2", define the IN parameter eno, and enter the employee number. If it is judged that the employee’s salary is lower than 3,000 yuan, the salary will be updated to 3,000 yuan; if the salary is greater than or equal to 3,000 yuan and less than 5,000 yuan, but the bonus ratio is NULL, the bonus ratio will be updated to 0.01; other salary increases are 100 yuan.

CREATE PROCEDURE update_sal_by_eno2(IN eno INT)
BEGIN
	DECLARE emp_sal DOUBLE;
	DECLARE emp_com DOUBLE;
	SELECT sal,comm INTO emp_sal,emp_com FROM emp WHERE empno=eno;
	IF emp_sal<3000
	THEN UPDATE emp SET sal=3000 WHERE empno=eno;
	ELSEIF emp_sal<5000 AND emp_com IS NULL
	THEN UPDATE emp SET comm=0.01*sal WHERE empno=eno;
	ELSE UPDATE emp SET sal=sal+800 WHERE empno=eno;
	END IF;
END;
CALL update_sal_by_eno2(7698);
SELECT * FROM emp WHERE empno=7698;

3.1.2 CASE of branch structure

Grammatical structure 1 of the CASE statement:

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

Grammatical structure 2 of the CASE statement:

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

Example 1 : Use the first format of the CASE flow control statement to judge whether the val value is equal to 1, equal to 2, or neither.

CASE val
	WHEN 1 THEN SELECT 'val is 1'; 
	WHEN 2 THEN SELECT 'val is 2';
	ELSE SELECT 'val is not 1 or 2'; 
END CASE;

Example 2 : Use the second format of the CASE flow control statement to determine whether val is empty, less than 0, greater than 0 or equal to 0.

CASE
	WHEN val IS NULL THEN SELECT 'val is null'; 
	WHEN val < 0 THEN SELECT 'val is less than 0';
	WHEN val > 0 THEN SELECT 'val is greater than 0'; 
	ELSE SELECT 'val is 0';
END CASE;

Example 3 : Declare the stored procedure "update_salary_by_eno4", define the IN parameter eno, and enter the employee number. Determine the department the employee belongs to. If he is in department No. 10, his salary will be increased by 500; if he is in department No. 20, his salary will be increased by 600;

CREATE PROCEDURE update_salary_by_eno4(IN eno INT)
BEGIN
	DECLARE emp_deptno INT;
	DECLARE emp_sal DOUBLE;
	SELECT deptno,sal INTO emp_deptno,emp_sal FROM emp WHERE empno=eno;
	CASE emp_deptno
	WHEN 10 THEN UPDATE emp SET sal=emp_sal+500 WHERE empno=eno;
	WHEN 20 THEN UPDATE emp SET sal=emp_sal+600 WHERE empno=eno;
	WHEN 30 THEN UPDATE emp SET sal=emp_sal+700 WHERE empno=eno;
	ELSE UPDATE emp SET sal=emp_sal+300 WHERE empno=eno;
END CASE;
END;
CALL update_salary_by_eno4(7698);
SELECT * FROM emp WHERE empno=7698;

Example 4 : Declare the stored procedure pro_sal_grade, define the IN parameter eno, and enter the employee number. Determine the salary level of the employee, if it is between [700,1200], it is level one; if it is between [1201,1400], it is level two; if it is between [1401,2000], it is level three; if If it is between [2001,3000], it is level four; if it is between [3001,9999], it is level five;

CREATE PROCEDURE sal_grade(IN eno INT) 
BEGIN
	DECLARE emp_sal INT; 

	SELECT sal INTO emp_sal FROM emps WHERE empno = eno;

	CASE 
		WHEN emp_sal>=700 AND emp_sal<=1200
			THEN SELECT '等级一'; 			
		WHEN emp_sal>=1201 AND emp_sal<=1400 
			THEN SELECT '等级二';		
		WHEN emp_sal>=1401 AND emp_sal<=2000 	
			THEN SELECT '等级三';
		WHEN emp_sal>=2001 AND emp_sal<=3000 
			THEN SELECT '等级四';
		WHEN emp_sal>=3001 AND emp_sal<=999 
			THEN SELECT '等级五';
	END CASE;
END //

3.2 Loop structure

3.2.1 LOOP of loop structure

The LOOP loop statement is used to repeatedly execute certain statements. The statements in LOOP are executed repeatedly until the loop is exited (using the LEAVE clause), and the loop process is exited.

The basic format of the LOOP statement is as follows:

[loop_label:] LOOP
		循环执行的语句
END LOOP [loop_label] 

Among them, loop_label indicates the label name of the LOOP statement, and this parameter can be omitted.

Example 1 : Use the LOOP statement to perform a loop operation. When the id value is less than 10, the loop process will be executed repeatedly.

DECLARE id INT DEFAULT 0;
add_loop:LOOP
   SET id = id +1;
   IF id >= 10 
   THEN LEAVE add_loop; 
   END IF;

END LOOP add_loop;

Example 2 : When the market environment improves, the company decides to raise everyone's salary in order to reward everyone. Declare the stored procedure "update_sal_loop()", declare the OUT parameter num, and output the number of loops. The cycle is implemented in the storage process to give everyone a salary increase, and the salary increase is 1.1 times the original. Until the average salary of the whole company reaches 8000. And count the number of cycles.

CREATE PROCEDURE update_sal_loop(OUT num INT) 
BEGIN
	DECLARE avg_sal DOUBLE; 
	DECLARE loop_count INT DEFAULT 0;

	SELECT AVG(sal) INTO avg_sal FROM emps;

	label_loop:LOOP
		IF avg_sal >= 8000 
		THEN LEAVE label_loop; 
		END IF;

		UPDATE emps SET sal = sal * 1.1; 
		SET loop_count = loop_count + 1;
		SELECT AVG(sal) INTO avg_salary FROM emps; 
	END LOOP label_loop;

SET num = loop_count; 
END ;

3.2.2 WHILE of loop structure

The WHILE statement creates a looping process with a conditional judgment. When WHILE executes a statement, it first judges the specified expression, if it is true, executes the statement in the loop, otherwise exits the loop. The basic format of the WHILE statement is as follows:

[while_label:] WHILE 循环条件 DO
   循环体
END WHILE [while_label];

while_label is the label name of the WHILE statement; if the result of the loop condition is true, the statements or statement groups in the WHILE statement are executed until the loop condition is false, and the loop is exited.

Example 1 : WHILE statement example, when the value of i is less than 10, the loop process will be executed repeatedly, the code is as follows:

CREATE PROCEDURE test_while()
BEGIN
   DECLARE i INT DEFAULT 0;

   WHILE i < 10 DO 
   	SET i = i + 1;
   END WHILE;

   SELECT i;
END ;
#调用
CALL test_while();

Example 2 : When the market environment is not good, the company decides to temporarily reduce everyone's salary in order to tide over the difficulties. Declare the stored procedure "update_salary_while()", declare the OUT parameter num, and output the number of cycles. The storage process implements a cycle to reduce everyone's salary, and the salary is reduced to 90% of the original. Until the average salary of the whole company reaches 3000. And count the number of cycles.

CREATE PROCEDURE update_sal_while(OUT num INT) 
BEGIN
	DECLARE avg_sal DOUBLE ;
	DECLARE while_count INT DEFAULT 0;
	SELECT AVG(sal) INTO avg_sal FROM emps; 
	WHILE avg_sal > 3000 DO
		UPDATE emps SET sal = sal * 0.9; 
		SET while_count = while_count + 1;
		SELECT AVG(sal) INTO avg_sal FROM emps; 
	END WHILE;

	SET num = while_count; 
END //

3.2.3 REPEAT of loop structure

The REPEAT statement creates a looping process with a conditional judgment. Different from the WHILE loop, the REPEAT loop will first execute the loop once, and then judge the expression in UNTIL. If the condition is met, it will exit, that is, END REPEAT; if the condition is not met, it will continue to execute the loop until it is satisfied and exit conditions.

The basic format of the REPEAT statement is as follows:

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

repeat_label is the label name of the REPEAT statement, and this parameter can be omitted; the statement or statement group in the REPEAT statement is repeated until expr_condition is true.

Example 1:

CREATE PROCEDURE test_repeat() 
BEGIN
	DECLARE i INT DEFAULT 0;

	REPEAT
		SET i = i + 1; 
	UNTIL i >= 10
	END REPEAT;

	SELECT i;
END ;

Example 2 : When the market environment improves, the company decides to raise everyone's salary in order to reward everyone. Declare the stored procedure "update_salary_repeat()", declare the OUT parameter num, and output the number of cycles. The cycle is implemented in the storage process to give everyone a salary increase, and the salary increase is 1.15 times the original. Until the average salary of the whole company reaches 9000. And count the number of cycles.

CREATE PROCEDURE update_salary_repeat(OUT num INT) 
BEGIN
	DECLARE avg_sal DOUBLE ;
	DECLARE repeat_count INT DEFAULT 0;
	
	SELECT AVG(sal) INTO avg_sal FROM emps; 
	
	REPEAT
		UPDATE emps SET sal = sal * 1.15;
        SET repeat_count = repeat_count + 1;
		SELECT AVG(sal) INTO avg_sal FROM emps; 
	UNTIL avg_sal >= 9000
	END REPEAT;

	SET num = repeat_count; 
END //

Compare the three loop structures:

1. All three types of loops can omit the name, but if a loop control statement (LEAVE or ITERATE) is added in the loop, the name must be added.

2. LOOP: generally used to implement a simple "dead" loop WHILE: first judge and then execute REPEAT: execute first and then judge, unconditionally execute at least once

3.3 Jump statement

3.3.1 The LEAVE statement of the jump statement

LEAVE statement: It can be used in a loop statement, or in a program body wrapped with BEGIN and END, to indicate the operation of jumping out of the loop or out of the program body. If you have experience in using process-oriented programming languages, you can understand LEAVE as break.

The basic format is as follows:

LEAVE 标记名

Among them, the label parameter represents the symbol of the cycle. LEAVE is used with BEGIN ... END or loops.

Example 1 : Create a stored procedure "leave_begin()" and declare an IN parameter num of type INT. Add a tag name to BEGIN...END, and use the IF statement in BEGIN...END to judge the value of the num parameter.

  • If num<=0, use the LEAVE statement to exit BEGIN...END;
  • If num=1, query the average salary of the "emps" table;
  • If num=2, query the minimum salary of the "emps" table;
  • If num>2, query the highest salary in the "emps" table.

Query the total number of people in the "emp" table after the IF statement ends.

CREATE PROCEDURE leave_begin(IN num INT) 
	begin_label: BEGIN
		IF num<=0
			THEN LEAVE begin_label; 
		ELSEIF num=1
			THEN SELECT AVG(sal) FROM emps; 
		ELSEIF num=2
			THEN SELECT MIN(sal) FROM emps; 
		ELSE
			SELECT MAX(sal) FROM emps; 
		END IF;

		SELECT COUNT(*) FROM emps; 
END ;

Example 2 : When the market environment is not good, the company decides to temporarily reduce everyone's salary in order to tide over the difficulties. Declare the stored procedure "leave_while()", declare the OUT parameter num, output the number of cycles, use the WHILE cycle in the stored procedure to reduce the salary to 90% of the original salary for everyone, until the average salary of the whole company is less than or equal to 10000, and count the number of cycles.

CREATE PROCEDURE leave_while(OUT num INT)
BEGIN
	#
	DECLARE avg_sal DOUBLE;#记录平均工资
	DECLARE while_count INT DEFAULT 0; #记录循环次数

	SELECT AVG(sal) INTO avg_sal FROM emps; #① 初始化条件

	while_label:WHILE TRUE DO #② 循环条件

		#③ 循环体
		IF avg_sal <= 10000 
			THEN LEAVE while_label;
		END IF;

		UPDATE emps SET sal = sal * 0.9; 
		SET while_count = while_count + 1;

		#④ 迭代条件
		SELECT AVG(sal) INTO avg_sal FROM emps; 
	END WHILE;
	#赋值
	SET num = while_count; 
END ;

3.3.2 ITERATE statement of jump statement

ITERATE statement: It can only be used in loop statements (LOOP, REPEAT and WHILE statements), which means to restart the loop and transfer the execution sequence to the beginning of the statement segment. If you have experience in using a process-oriented programming language, you can understand ITERATE as continue, which means "loop again".

The basic format of the statement is as follows:

ITERATE label

The label parameter indicates the label of the loop. The ITERATE statement must precede the loop flag.

Example: Define a local variable num with an initial value of 0. The num + 1 operation is performed in the loop structure.

  • If num < 10, continue to execute the loop;

  • If num > 15, exit the loop structure;

CREATE PROCEDURE test_iterate() 
BEGIN
	DECLARE num INT DEFAULT 0;

	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 //

4. Cursor

4.1 What is a cursor (or cursor)

Although we can also return a record through the filter conditions WHERE and HAVING, or the keyword LIMIT to limit the returned records, but we cannot locate a record forward or backward in the result set like a pointer, or 随意定位到某一条记录, and process the recorded data.

At this time, the cursor can be used. Cursor provides a flexible operation mode that allows us to locate each record in the result set and operate on the data in the pointed record. Cursors make SQL , a set-oriented language, capable of process-oriented development.

In SQL, a cursor is a temporary database object that can point to a data row pointer stored in a database table. Here the cursor acts as a pointer, and we can operate the data row by operating the cursor.

Cursors in MySQL can be used in stored procedures and functions.

For example, we query the employees whose salary is higher than 1500 in the emps data table:

SELECT empno,ename,sal FROM emps WHERE sal > 1500;

insert image description here

Here we can operate the data row through the cursor. As shown in the figure, the row where the cursor is located is the record of "7698". We can also scroll the cursor on the result set to point to any row in the result set.

4.2 Using cursor steps

Cursors must be declared before declaring handlers, and variables and conditions must also be declared before declaring cursors or handlers. If we want to use cursors, we generally need to go through four steps. The syntax for using cursors may vary slightly in different DBMSs.

The first step is to declare the cursor

In MySQL, use the DECLARE keyword to declare a cursor, and the basic form of its syntax is as follows:

DECLARE cursor_name CURSOR FOR select_statement;

This syntax works with MySQL, SQL Server, DB2 and MariaDB. If Oracle or PostgreSQL is used, it needs to be written as:

DECLARE cursor_name CURSOR IS select_statement;

To use the SELECT statement to obtain the data result set, and the traversal of the data has not yet started, here select_statement represents

A SELECT statement that returns a result set used to create a cursor.

for example:

DECLARE cur_emp CURSOR FOR
SELECT empno,sal FROM emps;
DECLARE cursor_dept CURSOR FOR 
SELECT deptno,dname, loc FROM depts ;

The second step is to open the cursor

The syntax for opening a cursor is as follows:

OPEN cursor_name

After we define the cursor, if we want to use the cursor, we must first open the cursor. When the cursor is opened, the query result set of the SELECT statement will be sent to the cursor work area to prepare for the subsequent cursor to read the records in the result set one by one.

OPEN cur_emp ;

The third step is to use the cursor (get data from the cursor)

The syntax is as follows:

FETCH cursor_name INTO var_name [, var_name] ...

The function of this sentence is to use the cursor_name to read the current row, and save the data to the variable var_name, and the cursor pointer points to the next row. If the data row read by the cursor has multiple column names, just assign multiple variable names after the INTO keyword.

Note: var_name must be defined before declaring the cursor.

FETCH cur_emp INTO emp_no, emp_sal ;

Note: The number of fields in the query result set of the cursor must be consistent with the number of variables behind INTO , otherwise, MySQL will prompt an error when the stored procedure is executed.

The fourth step, close the cursor

CLOSE cursor_name

If there is OPEN, there will be CLOSE, that is, to open and close the cursor. When we are done using the cursor, we need to close the cursor. Because the cursor will occupy system resources, if it is not closed in time, the cursor will remain until the end of the stored procedure , which will affect the efficiency of the system operation. The operation of closing the cursor will release the system resources occupied by the cursor.

After closing the cursor, we can no longer retrieve the data rows in the query results. If we need to retrieve, we can only open the cursor again.

CLOSE cur_emp; 

4.3 Example

Create a stored procedure "get_count_by_limit_total_salary()", declare the IN parameter limit_total_salary; declare the OUT parameter total_count. The function of the function can realize the accumulation of the salary values ​​of several employees with the highest salary until the total salary reaches the value of the limit_total_salary parameter, and return the accumulated number of people to total_count.

CREATE PROCEDURE get_count_by_limit_total_salary(IN limit_total_sal INT,OUT total_count INT)
BEGIN
	#声明变量
	DECLARE sum_sal INT DEFAULT  0;		#记录累加的总工资
	DECLARE emp_count INT DEFAULT  0;	#记录循环总次数
	DECLARE emp_sal INT;							#当前员工的工资
	
	#声明游标
	DECLARE  cursor_emp CURSOR FOR SELECT sal FROM emp ORDER BY sal DESC;
	#打开游标
	OPEN cursor_emp;
	#使用游标
	WHILE sum_sal < limit_total_sal DO
			FETCH cursor_emp INTO emp_sal;
			SET sum_sal = emp_sal+sum_sal;
			SET emp_count = emp_count+1;
	END WHILE;
	
	#关闭游标
	CLOSE cursor_emp;
	#设置传出参数值
	SET total_count = emp_count;
END;

4.4 Summary

Cursor is an important function of MySQL, which provides a perfect solution for reading the data in the result set one by one. Compared with implementing the same function at the application level, the cursor can be used in the stored program, which is more efficient and the program is more concise.

But at the same time, it will also bring some performance problems. For example, in the process of using the cursor, the data row will be locked. In this way, when the business concurrency is large, it will not only affect the efficiency of the business, but also consume system resources. Insufficient memory is caused because the cursor is processed in memory.

Suggestion: develop the habit of closing after use, so as to improve the overall efficiency of the system.

Guess you like

Origin blog.csdn.net/qq_72157449/article/details/132680045