MariaDB和存储过程:为什么游标迭代最后一行两次?

2nc8po8w  于 2022-11-08  发布在  其他
关注(0)|答案(1)|浏览(129)

MariaDB和存储过程:为何数据指标会使用来反覆运算最后一个数据列两次?
我有一个表tab,为了简单起见,它只包含一列id,列中的数字从1到3(见下面代码的第1部分)。我创建了一个游标(3)来检索tab中的每个数字,并将该数字作为IN参数输入到一个简短的过程(sp,第3部分)中。sp将该参数插入到表tab_ctrl中(ctrl用于控制)。
在运行光标(4)并选择tab_ctrl的内容后,我得到了以下结果:

+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  3 |  <- why?
+----+

tab的最后一行已经迭代了两次,为什么游标在第三行之后没有停止?

--**************************************
-- (1) Prepare tables
--**************************************

use test0;

-- Table to read each entry
DROP TABLE IF EXISTS tab;
CREATE TABLE tab  (
   id      INTEGER UNSIGNED DEFAULT NULL
 , PRIMARY KEY (id)
 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
 ;

INSERT INTO tab VALUES
 (1)
,(2)
,(3)
;

-- Table for controlling
DROP TABLE IF EXISTS tab_ctrl;
CREATE TABLE tab_ctrl (
   id      INTEGER UNSIGNED DEFAULT NULL
 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
 ;

--**************************************
-- (4) Run sp
--**************************************

CALL sp_cursor_add_records();
SELECT * FROM tab_ctrl;

--**************************************
-- (2) Stored procedure
--**************************************

DELIMITER //
DROP PROCEDURE IF EXISTS sp_add_records //
CREATE PROCEDURE sp_add_records(IN p_id INTEGER UNSIGNED)

BEGIN
  INSERT INTO tab_ctrl
  SELECT p_id
  ;    
END//

DELIMITER ;

--**************************************
-- (3) Cursor
--**************************************

DELIMITER //
DROP PROCEDURE IF EXISTS sp_cursor_add_records //
CREATE PROCEDURE sp_cursor_add_records()
BEGIN 
  -- Local variables
  DECLARE done            BOOLEAN DEFAULT 0;
  DECLARE p_id            INTEGER UNSIGNED;  

  -- Cursor
  DECLARE c CURSOR 
  FOR
  SELECT id
  FROM tab
  ORDER BY id
  ;

  -- Declare continue handler
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;

  -- Open cursor
  OPEN c;

  -- Loop through all rows
  REPEAT
    -- Get record
    FETCH c INTO p_id;

    -- Call add record procedure
    CALL sp_add_records(p_id);

  -- End of loop
  UNTIL done END REPEAT;

  -- Close cursor
  CLOSE c;

END//

DELIMITER ;
ulydmbyx

ulydmbyx1#

如果将循环重新构造为仅CALL sp_ad_records(p_id)(如果其为not done):

-- Declare continue handler
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;

  -- Open cursor
  OPEN c;

  -- Get First record
  FETCH c INTO p_id;

  -- Loop through all rows
  WHILE NOT done DO

    -- Call add record procedure
    CALL sp_add_records(p_id);

    -- Get next record
    FETCH c INTO p_id;

  -- End of loop
  END WHILE;

  -- Close cursor
  CLOSE c;

相关问题