MySQL must know 16 cursors: process centralized data one by one

The reading is compiled from "MySQL Must Know and Know" - Zhu Xiaofeng . For details, please log in to the purchase column on the official website of Geek Time .

A cursor is a data structure that can locate each record in the result set and operate on the data in the pointed record.

Cursor usage steps

Cursors can only be used within stored procedures, which include stored procedures and stored functions.

create function 函数名称(参数) return 数据类型 程序体

Stored functions are similar to stored procedures, with several differences:

  • A stored function must return a value or a data table, and a stored procedure may not return
  • Stored procedures can be called through the CALL statement, stored functions cannot
  • Stored functions can be used in query statements, but stored procedures cannot
  • The functions of stored procedures are more powerful, including the ability to perform operations on tables (such as creating tables, deleting tables, etc.) and transaction operations, which are not available in stored functions

When using cursors, there are mainly 4 steps

  1. define cursor

    declare 游标名 cursor for 查询语句;
    

    Declare a cursor, the data set it can operate is the result set returned by the "query statement".

  2. open cursor

    open 游标名称;
    

    After the cursor is opened, the system will prepare the query result set for the cursor, and prepare for the subsequent cursor to read the records in the result set one by one.

  3. Read data from the cursor's data result set

    fetch 游标名 into 变量列表;
    

    Through the cursor, assign the data of the record in the result set pointed by the current cursor to the variable in the list.

    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.

  4. close cursor

    close 游标名;
    

    After using the cursor, be sure to remember to close the cursor in time. 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.


the case

In the purchase module of the supermarket project, there is a function to check and accept the data of the purchase order. In fact, after the data of the purchase order is confirmed to be correct, the data of the purchase order is processed, including increasing the inventory of the purchased goods and modifying the average purchase price of the goods .

Import head table (demo.importhead)

Listnumber Supplierid Stockid Operators Totalquantity Total value Recordingdate
1234 1 1 1 8 171 2020-12-12

Purchase Order Details (demo.importdetails)

Listnumber Itemnumber Quantity Importprice Importvalue
1234 1 5 33 165
1234 2 3 2 6

Inventory table (demo.inventory)

Stocknumber Itemnumber Invquantity
1 1 10
1 2 20

Goods Information Form (demo.goodsmaster)

Itemnuber Barcode Goodsname Specification Unit Salesprice Avg import price
1 0001 Book 16K Book 89 30
2 0002 Pen NULL branch 5 3

To check and accept the purchase order, two operations need to be performed on each purchased product:

  1. On the basis of the existing inventory quantity, add the quantity purchased this time;
  2. According to the price and quantity of this purchase, the average purchase price and inventory of existing commodities, calculate the new average purchase price: (this purchase price * this purchase quantity + average purchase price of existing commodities * existing commodity inventory) / (this purchase quantity + existing inventory quantity).

Because the operation process needs to be controlled through the application program, a loop operation is made, and only the data records of one commodity are queried and processed at a time until all the data in the purchase order are processed. In this way, the application must send a lot of SQL commands to the server and interact with the server a lot, which not only complicates the code, but also is not secure enough. It's easy if you use cursors. Because all operations can be done on the server side, the application only needs to send a command to call the stored procedure.

Created a stored procedure demo.mytest()

mysql> delimiter //
mysql> create procedure demo.mytest(mylistnumber int)
-> begin
-> declare mystockid int;
-> declare myitemnumber int;
-> declare myquantity decimal(10,3);
-> declare myprice decimal(10,2);
-> declare done int default FALSE; -- 用来控制循环结束
-> declare cursor_importdata cursor for -- 定义游标
-> select b.stockid, a.itemnumber, a.quantity, a.importprice
-> from demo.importdetails as a
-> join demo.importhead as b
-> on (a.listnumber=b.listnumber)
-> where a.listnumber = mylistnumber;
-> declare continue handler for not found set done = true; -- 条件处理语句
->
-> open cursor_importdata; -- 打开游标
-> fetch cursor_importdata into mystockid, myitemnumber, myquantity, myprice; -- 读入第一条记录
-> repeat
-> -- 更新商品进价
-> update demo.goodsmaster as a, demo.inventory as b
-> set a.avgimportprice = (a.avgimportprice*b.invquantity+myprice*myquantity)/(b.invquantity+myquantity)
-> where a.itemnumber=b.itemnumber and b.stockid=mystockid and a.itemnumber=myitemnumber;
-> -- 更新商品库存
-> udpate demo.inventory
-> set invquantity = invquantity + myquantity
-> where stockid = mystockid and itemnumber=myitemnumber;
-> -- 获取下一条记录
-> fetch cursor_importdata into mystockid, myitemnumber, myquantity, myprice;
-> until done end repeat;
-> close cursor_importdata;
-> end
-> //
Query OK, 0 rows affected (0.02 sec)
-> delimiter ;

The core operation of this code has 6 steps:

  1. Change the MySQL delimiter to "//"
  2. After starting the program body, 4 variables are defined, namely mystockid, myitemnumber, myquantity and myprice. The function of these variables is to store the warehouse number, commodity number, purchase quantity and purchase price data read from the cursor.
  3. Define a cursor. The name of the cursor is specified here, as well as the data set that the cursor can handle (detailed data of all goods purchased in the purchase order specified by mylistnumber).
  4. Define the conditional processing statement declare continue handler for not found set done = true; .
  5. Open the cursor, read in the first record, and start performing data operations.
  6. Close the cursor and end the program.

The stored procedure for handling purchase order acceptance is created. Run this stored procedure to see if you can get the desired result:

mysql> CALL demo.mytest(1234);          -- 调用存储过程,验收单号是1234的进货单
Query OK, 0 rows affected (11.68 sec)   -- 执行成功了
 
mysql> select * from demo.inventory;    -- 查看库存,已经改过来了
+---------+------------+-------------+
| stockid | itemnumber | invquantity |
+---------+------------+-------------+
| 1 | 1 | 15.000 |
| 1 | 2 | 23.000 |
+---------+------------+-------------+
2 rows in set (0.00 sec)
 
mysql> select * from demo.goodsmaster;     -- 查看商品信息表,平均进价也改过来了
+------------+---------+-----------+---------------+------+------------+----------------+
| itemnumber | barcode | goodsname | specification | unit | salesprice | avgimportprice |
+------------+---------+-----------+---------------+------+------------+----------------+
| 1 | 0001 || 16|| 89.00 | 31.00 |
| 2 | 0002 || NULL || 5.00 | 2.87 |
+------------+---------+-----------+---------------+------+------------+----------------+
2 rows in set (0.00 sec)

sentence

conditional statement

declare 处理方式 handler for 问题 操作;
  1. The "problem" in the grammatical structure refers to what problem was encountered in the SQL operation. For example, the problem here is "NOT FOUND", which means that the cursor has reached the end of the result set and there are no records. That is, all records in the dataset have been processed.
  2. The operation to be executed is "SET done=TRUE", and done is a flag defined to identify whether the data in the dataset has been processed. done=TRUE, which means the data processing is completed.
  3. There are two options for the processing method, namely "CONTINUE" and "EXIT", which means that after encountering a problem and executing the "operation" in the grammatical structure, whether to choose to continue running the program, or to choose to exit and end the program.

flow control statement

MySQL's flow control statements can only be used for stored programs, and there are mainly three types.

  • Jump statements: iterate and leave statements

    • iterate can only be used in a loop statement, which means restarting the loop
    • leave 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
  • Looping Statements: loop, while, and repeat statements

    • loop

      标签:LOOP
      操作
      END LOOP 标签;
      
    • while

      WHILE 条件 DO
      操作
      END WHILE;
      

      The WHILE loop determines whether to continue to execute the operation in the loop by judging whether the condition is true. It should be noted that the WHILE loop first judges the condition, and then executes the operation in the loop body.

    • repeat

      REPEAT
      操作
      UNTIL 条件 END REPEAT

      The REPEAT loop also determines whether to continue to execute the operation in the loop by judging whether the condition is true. Unlike WHILE, the REPEAT loop executes the operation first and then judges the condition.

  • Conditional judgment statement: if statement and case statement

    • if

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

      The characteristic of the IF statement is that different expressions correspond to different operations

    • case

      CASE 表达式
      WHEN1 THEN 操作1
      [WHEN2 THEN 操作2]……
      [ELSE 操作N]
      END CASE;
      

      The characteristic of the CASE statement is that different values ​​of the expression correspond to different operations.

There is a small problem to pay attention to: if one operation needs to use the result of another operation, the order of operations must not be mistaken.


Test questions

Suppose there is a data table test.cursor, the specific information is as follows:

mysql> select * from test.table_cursor;
+----+----------+
| id | quantity |
+----+----------+
|  1 |      100 |
|  2 |      101 |
|  3 |      102 |
|  4 |      103 |
+----+----------+

Write a simple stored procedure, use a cursor to process the data in a data table one by one, and require: records with even numbers, quant=quanit+1; records with odd numbers, quant=quanit+2.

delimiter //
create procedure test.procedure_cursor()
begin
declare t_id int;
declare t_quantity int;
declare done int default false;
declare t_cursor cursor for select * from test.table_cursor;
declare continue handler for not found set done = true;

open t_cursor;
fetch t_cursor into t_id, t_quantity;
repeat 
if (t_id mod 2 = 0) then 
update test.table_cursor set quantity = quantity + 1 where id = t_id;
else 
update test.table_cursor set quantity = quantity + 2 where id = t_id;
end if;
fetch t_cursor into t_id, t_quantity;
until done end repeat;
close t_cursor;
end
//
delimiter ;

transfer:

mysql> call test.procedure_cursor();
Query OK, 0 rows affected (0.03 sec)

mysql> select * from test.table_cursor;
+----+----------+
| id | quantity |
+----+----------+
|  1 |      102 |
|  2 |      102 |
|  3 |      104 |
|  4 |      104 |
+----+----------+
4 rows in set (0.00 sec)

Guess you like

Origin blog.csdn.net/qq_31362767/article/details/124511262