Chapter 16_ Variables, Flow Control, and Cursors

Chapter 16_ Variables, Flow Control, and Cursors


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 user-defined, and belong to 服务器layers. 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. These system variables define the attributes and characteristics of the current MySQL service instance. The values ​​of these system variables are either 编译MySQL时参数the default values ​​of , or 配置文件the parameter values ​​in (eg my.ini, etc.). You can https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.htmlview .

System variables are divided into global system variables ( globalkeywords need to be added) and session system variables ( sessionkeywords ). Sometimes global system variables are referred to as global variables for short, and session system variables are sometimes called local variables. **If not written, the default 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:

image-20211108114846634

  • Global system variables are valid for all sessions (connections), but不能跨重启
  • 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 两个“@”, where "@@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, database administrators need to modify the default values ​​of system variables in order to modify the properties and characteristics of the current session or MySQL service instance. specific method:

Method 1: Modify MySQL 配置文件, 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.tx_isolation;
SET @@session.tx_isolation='read-uncommitted';
SET GLOBAL max_connections = 1000;
SELECT @@global.max_connections;

1.2 User variables

1.2.1 Classification of user variables

User variables are defined by users themselves. As a MySQL coding standard, user variables in MySQL begin with 一个“@”. 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 sessions.

  • Local variables: valid only in BEGIN and END statement blocks. Local variables can only 存储过程和函数be used in .

1.2.2 Session User Variables

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

#方式2:“:=” 或 INTO关键字
SELECT @用户变量 := 表达式 [FROM 等子句];
SELECT 表达式 INTO @用户变量  [FROM 等子句];

  • View the value of a user variable (view, compare, operate, etc.)
SELECT @用户变量
  • example
SET @a = 1;

SELECT @a;
SELECT @num := COUNT(*) FROM employees;

SELECT @num;
SELECT AVG(salary) INTO @avgsalary FROM employees;

SELECT @avgsalary;
SELECT @big;  #查看某个未声明的变量时,将得到NULL值

1.2.3 Local variables

Definition: DECLAREA local variable can be defined using the statement

Scope: valid only 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 myparam 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. Use variables (view, compare, operate, etc.)

SELECT 局部变量名;

Example 1: Declare local variables and assign them to last_name and salary with employee_id 102 in the employees table

DELIMITER //

CREATE PROCEDURE set_value()
BEGIN
	DECLARE emp_name VARCHAR(25);
	DECLARE sal DOUBLE(10,2);
	
	SELECT last_name,salary INTO emp_name,sal
	FROM employees 
	WHERE employee_id = 102;
	
	SELECT emp_name,sal;
END //

DELIMITER ;

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

#方式1:使用用户变量
SET @m=1;
SET @n=1;
SET @sum=@m+@n;

SELECT @sum;
#方式2:使用局部变量
DELIMITER //

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

DELIMITER ;

Example 3: Create a stored procedure "different_salary" to query the salary gap between an employee and his leader, and use the IN parameter emp_id to receive the employee id, and use the OUT parameter dif_salary to output the salary gap result.

#声明
DELIMITER //

CREATE PROCEDURE different_salary(IN emp_id INT,OUT dif_salary DOUBLE)
BEGIN
	#声明局部变量
	DECLARE emp_sal,mgr_sal DOUBLE DEFAULT 0.0;
	DECLARE mgr_id INT;
	
	SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id;
	SELECT manager_id INTO mgr_id FROM employees WHERE employee_id = emp_id;
	SELECT salary INTO mgr_sal FROM employees WHERE employee_id = mgr_id;
	SET dif_salary = mgr_sal - emp_sal;

END //

DELIMITER ;

#调用
SET @emp_id = 102;
CALL different_salary(@emp_id,@diff_sal);


#查看
SELECT @diff_sal;

1.2.4 Comparing session user variables and local variables

			  作用域					定义位置				  语法
会话用户变量	  当前会话				   会话的任何地方				加@符号,不用指定类型
局部变量	   定义它的BEGIN END中 		BEGIN END的第一句话		  一般不用加@,需要指定类型

2. Define conditions and handlers

定义条件It is to define the problems that may be encountered during the execution of the program in advance, 处理程序define the processing methods that should be taken when encountering problems, and ensure 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 "UpdateDataNoCondition". code show as below:

DELIMITER //

CREATE PROCEDURE UpdateDataNoCondition()
	BEGIN
		SET @x = 1;
		UPDATE employees SET email = NULL WHERE last_name = 'Abel';
		SET @x = 2;
		UPDATE employees SET email = 'aabbel' WHERE last_name = 'Abel';
		SET @x = 3;
	END //

DELIMITER ;

Call the stored procedure:

mysql> CALL UpdateDataNoCondition();
ERROR 1048 (23000): Column 'email' 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 a 错误名字and . 指定的错误条件This name can then be used in statements defining handlers DECLARE HANDLER.

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

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

Description of the error code:

  • MySQL_error_codeand sqlstate_valueboth can 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 1418 (HY000), 1418 is MySQL_error_code and 'HY000' is sqlstate_value.
  • For example, in ERROR 1142 (42000), 1142 is MySQL_error_code and '42000' is sqlstate_value.

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

#使用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 "ERROR 1148 (42000)" error, the name is 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.
  • The 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 simple statements like " ", or compound statements written SET 变量 = 值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 value of sqlstate_value, execute the CONTINUE operation when the value of MySQL_error_code is 1048, and set the value of @proc_value to -1.

DELIMITER //

CREATE PROCEDURE UpdateDataNoCondition()
	BEGIN
		#定义处理程序
		DECLARE CONTINUE HANDLER FOR 1048 SET @proc_value = -1;
		
		SET @x = 1;
		UPDATE employees SET email = NULL WHERE last_name = 'Abel';
		SET @x = 2;
		UPDATE employees SET email = 'aabbel' WHERE last_name = 'Abel';
		SET @x = 3;
	END //

DELIMITER ;

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 departments
AS
SELECT * FROM atguigudb.`departments`;

ALTER TABLE departments
ADD CONSTRAINT uk_dept_name UNIQUE(department_id);
DELIMITER //

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 departments(department_name) VALUES('测试');
		SET @x = 2;
		INSERT INTO departments(department_name) VALUES('测试');
		SET @x = 3;
	END //

DELIMITER ;

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:

  • 顺序结构: The program is executed sequentially from top to bottom
  • 分支结构: The program is selected and executed according to the conditions, and one of the two or more paths is selected for execution
  • 循环结构: When the program meets certain conditions, execute a set of statements repeatedly

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

  • 条件判断语句: IF statement and CASE statement
  • 循环语句: LOOP, WHILE, and REPEAT statements
  • 跳转语句: ITERATE and LEAVE statements

3.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 ② Used in 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_salary_by_eid1", define the IN parameter emp_id, and enter the employee number. It is judged that if the salary of the employee is less than 8,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.

    DELIMITER //
    
    CREATE PROCEDURE update_salary_by_eid1(IN emp_id INT)
    BEGIN
    	DECLARE emp_salary DOUBLE;
    	DECLARE hire_year DOUBLE;
    
    	SELECT salary INTO emp_salary 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_salary < 8000 AND hire_year > 5
    	THEN UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_id;
    	END IF;
    END //
    
    
    DELIMITER ;
    
  • Example 3: Declare the stored procedure "update_salary_by_eid2", define the IN parameter emp_id, and enter the employee number. It is judged that if the employee's salary is less than 9,000 yuan and the employee has been employed for more than 5 years, the salary will be increased by 500 yuan; otherwise, the salary will be increased by 100 yuan.

    DELIMITER //
    
    CREATE PROCEDURE update_salary_by_eid2(IN emp_id INT)
    BEGIN
    	DECLARE emp_salary DOUBLE;
    	DECLARE hire_year DOUBLE;
    
    	SELECT salary INTO emp_salary 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_salary < 8000 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 ;
    
  • Example 4: Declare the stored procedure "update_salary_by_eid3", define the IN parameter emp_id, and enter the employee number. If it is judged that the employee’s salary is lower than 9,000 yuan, the salary will be updated to 9,000 yuan; if the salary is greater than or equal to 9,000 yuan and less than 10,000 yuan, but the bonus ratio is NULL, the bonus ratio will be updated to 0.01; other salary increase is 100 yuan.

    DELIMITER //
    
    CREATE PROCEDURE update_salary_by_eid3(IN emp_id INT)
    BEGIN
    	DECLARE emp_salary DOUBLE;
    	DECLARE bonus DECIMAL(3,2);
    
    	SELECT salary INTO emp_salary FROM employees WHERE employee_id = emp_id;
    	SELECT commission_pct INTO bonus FROM employees WHERE employee_id = emp_id;
    
    	IF emp_salary < 9000
    		THEN UPDATE employees SET salary = 9000 WHERE employee_id = emp_id;
    	ELSEIF emp_salary < 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 ;
    

3.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 determine 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_eid4", define the IN parameter emp_id, and enter the employee number. If it is judged that the employee’s salary is lower than 9,000 yuan, the salary will be updated to 9,000 yuan; if the salary is greater than or equal to 9,000 yuan and less than 10,000 yuan, but the bonus ratio is NULL, the bonus ratio will be updated to 0.01; the other salary increase is 100 yuan.
DELIMITER //

CREATE PROCEDURE update_salary_by_eid4(IN emp_id INT)
BEGIN
	DECLARE emp_sal DOUBLE;
	DECLARE bonus DECIMAL(3,2);

	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 ;
  • Example 4: Declare the stored procedure update_salary_by_eid5, define the IN parameter emp_id, and enter the employee number. Judging the employee's entry years, if it is 0 years, the salary will increase by 50; if it is 1 year, the salary will increase by 100; if it is 2 years, the salary will increase by 200; if it is 3 years, the salary will increase by 300; 400; other salary increases 500.
DELIMITER //

CREATE PROCEDURE update_salary_by_eid5(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 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 ;

3.3 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 the 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 wages for everyone in order to reward everyone. Declare the stored procedure "update_salary_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 12,000. And count the number of cycles.

DELIMITER //

CREATE PROCEDURE update_salary_loop(OUT num INT)
BEGIN
	DECLARE avg_salary DOUBLE;
	DECLARE loop_count INT DEFAULT 0;
	
	SELECT AVG(salary) INTO avg_salary FROM employees;
	
	label_loop:LOOP
		IF avg_salary >= 12000 THEN LEAVE label_loop;
		END IF;
		
		UPDATE employees SET salary = salary * 1.1;
		SET loop_count = loop_count + 1;
		SELECT AVG(salary) INTO avg_salary FROM employees;
	END LOOP label_loop;
	
	SET num = loop_count;

END //

DELIMITER ;

3.4 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:

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

DELIMITER //

CREATE PROCEDURE test_while()
BEGIN	
	DECLARE i INT DEFAULT 0;
	
	WHILE i < 10 DO
		SET i = i + 1;
	END WHILE;
	
	SELECT i;
END //

DELIMITER ;
#调用
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 5000. And count the number of cycles.

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;
	
	SET num = while_count;

END //

DELIMITER ;

3.5 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:

DELIMITER //

CREATE PROCEDURE test_repeat()
BEGIN	
	DECLARE i INT DEFAULT 0;
	
	REPEAT 
		SET i = i + 1;
	UNTIL i >= 10
	END REPEAT;
	
	SELECT i;
END //

DELIMITER ;

Example 2: When the market environment improves, the company decides to raise wages for everyone 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 13,000. And count the number of cycles.

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;
	
	SET num = repeat_count;
		
END //

DELIMITER ;

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.6 LEAVE statement of 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 loop. LEAVE is used with BEGIN ... END or loops.

**Example 1:** Create the stored procedure "leave_begin()", and declare the IN parameter num of INT type. 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 "employees" table;
  • If num=2, query the minimum salary of the "employees" table;
  • If num>2, query the maximum salary of the "employees" table.

After the IF statement, query the total number of employees in the "employees" table.

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 ;

Example 2:

When the market environment is not good, the company decided 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.

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 ;

3.7 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;
DELIMITER //

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

DELIMITER ;

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 充当了指针的作用, we can operate the data row by manipulating the cursor.

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

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

SELECT employee_id,last_name,salary FROM employees
WHERE salary > 15000;

image-20211111182656990

Here we can use the cursor to operate the data row. As shown in the figure, the row where the cursor is located is the "108" record. 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 data has not been traversed at this time, here select_statement represents the SELECT statement, returning a result set for creating a cursor.

for example:

DECLARE cur_emp CURSOR FOR 
SELECT employee_id,salary FROM employees;
DECLARE cursor_fruit CURSOR FOR 
SELECT f_name, f_price FROM fruits ;

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 records in the result set of the cursor .

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_id, 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 占用系统资源, 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 the stored procedure "get_count_by_limit_total_salary()", declare the IN parameter limit_total_salary, DOUBLE type; declare the OUT parameter total_count, INT type. 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.

DELIMITER //

CREATE PROCEDURE get_count_by_limit_total_salary(IN limit_total_salary DOUBLE,OUT total_count INT)

BEGIN
	DECLARE sum_salary DOUBLE DEFAULT 0;  #记录累加的总工资
	DECLARE cursor_salary DOUBLE DEFAULT 0; #记录某一个工资值
	DECLARE emp_count INT DEFAULT 0; #记录循环个数
	#定义游标
	DECLARE emp_cursor CURSOR FOR SELECT salary FROM employees ORDER BY salary DESC;
	#打开游标
	OPEN emp_cursor;
	
	REPEAT
		#使用游标(从游标中获取数据)
		FETCH emp_cursor INTO cursor_salary;
		
		SET sum_salary = sum_salary + cursor_salary;
		SET emp_count = emp_count + 1;
		
		UNTIL sum_salary >= limit_total_salary
	END REPEAT;
	
	SET total_count = emp_count;
	#关闭游标
	CLOSE emp_cursor;
	
END //

DELIMITER ;

4.5 Summary

Cursor is an important function of MySQL, which 逐条读取provides a perfect solution for the data in the result set. 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, data rows will be processed. In 加锁this way, when the business concurrency is large, it will not only affect the efficiency between businesses, but also 消耗系统资源cause insufficient memory. 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.

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 will only be used 临时生效. 数据库重启After that, the server will read the default value of the variable from the MySQL configuration file.
The MySQL 8.0 version adds new SET PERSISTcommands. 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 mysqld-auto.cnfa file in the data directory, and it will read the file when it is started next time, 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)

Guess you like

Origin blog.csdn.net/qq_29216579/article/details/130804570