"MySQL must know will be" a bug Chapter 24

The twenty-fourth to twentieth chapters

XXIV

Sometimes, the need to move forward or backward in one or more rows retrieved row, which is the cursor, the cursor is stored in a MySQL database queries on the server, not a SELECT statement, but the statement was retrieved result set

Cursor is mainly used for interactive applications, users can scroll through the data on the screen to browse or change

MySQL cursor can only be used for stored procedures (and function)

Use steps

1, the statement (define) the cursor

2, open the cursor, this process is the actual data retrieved

3, retrieved as required to obtain each row

4, close the cursor

Create, open and close the cursor and

CREATE PROCEDURE processorders()
BEGIN
	-- 定义游标
	DECLARE ordernumbers CURSOR
	FOR
	SELECT order_num FROM orders;
	
	-- 打开游标
	OPEN ordernumbers;
	
	-- 关闭游标
	CLOSE ordernumbers;
	
END;

Is to be noted OPEN xxx, CLOSE xxx statement should be stored in the procedure (between the BEGIN ... END), whether used alone being given

FETCH using separate visits each row, the row pointer moves forward inside the cursor, so that the next FETCH statement retrieves the next line to ensure that no repeat read

CREATE PROCEDURE processorders()
BEGIN
	--定义一个局部变量
	DECLARE o INT;
	
	DECLARE ordernumbers CURSOR
	FOR
	SELECT order_num FROM orders;
	
	OPEN ordernumbers;
	
	--检索第一行
	FETCH ordernumbers INTO o;
	
	CLOSE ordernumbers;

END;

The first row of the retrieved stored into local variables o but not processed

Cyclic retrieve data from the first row to the last row

CREATE PROCEDURE processorders()
BEGIN

	--定义局部变量,必须在定义游标之前定义
	DECLARE done BOOLEAN DEFAULT 0;
	DECLARE o INT;
	
	DECLARE ordernumbers CURSOR
	FOR
	SELECT order_num FROM orders;
	
	DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
	
	OPEN ordernumbers;
	
	--循环每一行
	REPEAT
		FETCH ordernumbers INTO o;
	UNTIL done END REPEAT;
	
	CLOSE ordernumbers;
	
END;

The present embodiment is repeatedly executed until done FETCH is true, it is done with a defined start DEFAULT 0, and when done As is true

DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;

This statement defines a CONTINUE HANDLER, when SQLSTATE '02000' occurs, SET done = 1, SQLSTATE '02000' is a condition not found, this condition occurs when there are no more rows due REPEAT loop can not continue for

Processing data retrieved

-- 上一章学习过的存储过程,待会要用到
CREATE PROCEDURE ordertotal(
	IN onumber INT,
	IN taxable BOOLEAN,
	OUT ototal DECIMAL(8,2)
)	COMMENT 'Obtain order total, optionally adding tax'
BEGIN

	DECLARE total DECIMAL(8,2);
	DECLARE taxrate INT DEFAULT 6;
	
	SELECT Sum(item_price*quantity)
	FROM orderitems
	WHERE order_num = onumber
	INTO total;
	
	IF taxable THEN
		SELECT total+(total/100*taxrate) INTO total;
	END IF;
	
	SELECT total INTO ototal;
	
END;
-- 如果已经存在该过程,先删除
DROP PROCEDURE IF EXISTS processorders;

CREATE PROCEDURE processorders()
BEGIN
    -- Declare local variables
    DECLARE done BOOLEAN DEFAULT 0;
    DECLARE o INT;
    DECLARE t DECIMAL(8, 2);
    
    -- Declare the cursor
    DECLARE ordernumbers CURSOR
    FOR
    SELECT order_num FROM orders;
    
    -- Declare continue handler
    DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
    
    -- 如果表已经存在,先删除
	DROP TABLE IF EXISTS ordertotals;
    -- 创建表
    CREATE TABLE IF NOT EXISTS ordertotals (order_num INT, total DECIMAL(8, 2));
    
    -- Open the cursor
    OPEN ordernumbers;
    
    -- Loop through all rows
    REPEAT
    
        -- 取第一行
        FETCH ordernumbers INTO o;
        
        -- done仍为0
		IF NOT done THEN
        	-- 调用存储过程,将结果赋值给t 
			CALL ordertotal(o, 1, t);
        	-- 插入一行到新建的表中
			INSERT INTO ordertotals(order_num, total)
						VALUES(o, t);
				
		END IF;
 
    -- End of loop
    UNTIL done END REPEAT;
    
    -- Close the cursor  
    CLOSE ordernumbers;
END;

-- CREATE只相当于声明一个过程,CALL是调用,若没有该语句而执行接下来的SELECT语句,报错:表不存在
CALL processorders;

-- 查看该表
SELECT *
FROM ordertotals;

We have added a variable t, used to store each order with tax together, the results ordertotals table stores generated

Here the code with different code books, a bug in the code book, resulting in the output line of the last two results, a bug in code look

REPEAT
	FETCH ordernumbers INTO o;
	
	CALL ordertotal(o, 1, t);
	
	INSERT INTO ordertotals(order_num, total)
	VALUES(o, t);
	
UNTIL done END REPEAT;

Probably for the following reasons, after the final row, back to the beginning of the cycle, MySQL attempts to FETCH a new line, but at this time has no more lines can be retrieved, this time done to 1, in theory, it should end error cycles, but not so MySQL, but to continue the cycle, and O, the value of a cycle value t, resulting in the table have duplicate the last two rows, since after this cycle is done 1 therefore exit the loop, which is why cycling body's own code to judge one more time, when it is no longer done for the subsequent operations 1

Detailed explanation and supplement

Published 84 original articles · won praise 7 · views 10000 +

Guess you like

Origin blog.csdn.net/weixin_43569916/article/details/104541183