使用INTO内部游标的MySQL / MariaDB设置值具有不正确的迭代

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用INTO内部游标的MySQL / MariaDB设置值具有不正确的迭代相关的知识,希望对你有一定的参考价值。

有人可以解释一下为什么我运行这段代码:

    BEGIN
        -- Declare loop constructs --
        DECLARE done INT DEFAULT FALSE; 

        -- Declare Person variables --
        DECLARE s_trnsf_id INT(11) DEFAULT NULL;
    DECLARE s_trnsf_trnsp_id INT(11) DEFAULT NULL;
    DECLARE s_trnsf_bacc_id INT(11) DEFAULT NULL;
    DECLARE s_trnsf_cus_id INT(11) DEFAULT NULL;
    DECLARE s_trnsf_bacc_amnt DECIMAL(18,4) DEFAULT NULL;
    DECLARE s_trnsf_recidue_amnt DECIMAL(18,4) DEFAULT NULL;

    DECLARE t_trnsf_id INT(11) DEFAULT NULL;
    DECLARE t_trnsf_recidue_amnt DECIMAL(18,4) DEFAULT NULL;

    DECLARE c1 INT(11) DEFAULT 0;

        -- Declare Cursor --
        DECLARE member_cursor CURSOR FOR 
            SELECT trnsf_id, trnsf_trnsp_id, trnsf_bacc_id, trnsf_cus_id, trnsf_bacc_amnt,trnsf_recidue_amnt
    FROM d_transfers
    WHERE 
    trnsf_bacc_amnt < 0
    AND trnsf_recidue_amnt <> 0
    ORDER BY #trnsf_trnsp_id ASC, trnsf_bacc_id ASC, trnsf_cus_id ASC, 
    trnsf_transfer_ts ASC;

        -- Declare Continue Handler --
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

        OPEN member_cursor;

        read_loop: LOOP

    SET c1 = c1+1;

            -- Fetch data from cursor --
            FETCH member_cursor 
            INTO s_trnsf_id,
    s_trnsf_trnsp_id,
    s_trnsf_bacc_id,
    s_trnsf_cus_id,
    s_trnsf_bacc_amnt,
    s_trnsf_recidue_amnt;

            -- Exit loop if finished --
            IF done THEN
                LEAVE read_loop;
            END IF;

    ##MARKED_BEGIN######################  
    SELECT trnsf_id#,trnsf_recidue_amnt 
    into t_trnsf_id#,t_trnsf_recidue_amnt 
    from d_transfers 
    WHERE trnsf_bacc_amnt > 0
    AND trnsf_recidue_amnt > 0
    AND trnsf_trnsp_id = s_trnsf_trnsp_id
    AND trnsf_bacc_id = s_trnsf_bacc_id
    AND trnsf_cus_id = s_trnsf_cus_id 
    ORDER BY trnsf_transfer_ts ASC limit 1;
    ##MARKED_END######################  


    END LOOP read_loop;

        CLOSE member_cursor;

    SELECT c1;

    END

它返回:

+-------+
| c1    |
+-------+
| 138 |
+-------+

但是,如果我用代码替换MARKED_BEGIN和MARKED_END之间的代码:

SET t_trnsf_id = (
SELECT trnsf_id#,trnsf_recidue_amnt 
FROM d_transfers 
WHERE trnsf_bacc_amnt > 0
AND trnsf_recidue_amnt > 0
AND trnsf_trnsp_id = s_trnsf_trnsp_id
AND trnsf_bacc_id = s_trnsf_bacc_id
AND trnsf_cus_id = s_trnsf_cus_id 
ORDER BY trnsf_transfer_ts ASC limit 1 
); 

我明白了:

+-------+
| c1    |
+-------+
| 54742 |
+-------+

我认为它应该返回相同的结果!

如果我排除

AND trnsf_trnsp_id = s_trnsf_trnsp_id
AND trnsf_bacc_id = s_trnsf_bacc_id
AND trnsf_cus_id = s_trnsf_cus_id

从上面的代码返回正确的迭代(select语句中的行数)

我在MacOS上使用MariaDB 10.1.10

答案

@Solarflare,谢谢你的提示!添加CONTINUE HANDLER可以解决问题。

BEGIN
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = FALSE;
  BEGIN
    -- body of handler

    ##MARKED_BEGIN######################  
    SELECT trnsf_id,trnsf_recidue_amnt 
    into t_trnsf_id,t_trnsf_recidue_amnt 
    from d_transfers 
    WHERE trnsf_bacc_amnt > 0
    AND trnsf_recidue_amnt > 0
    AND trnsf_trnsp_id = s_trnsf_trnsp_id
    AND trnsf_bacc_id = s_trnsf_bacc_id
    AND trnsf_cus_id = s_trnsf_cus_id 
    ORDER BY trnsf_transfer_ts ASC limit 1;
    ##MARKED_END######################  

  END;
END;

以上是关于使用INTO内部游标的MySQL / MariaDB设置值具有不正确的迭代的主要内容,如果未能解决你的问题,请参考以下文章

MySql数据库的存储过程能返回游标么?

mysql之游标

PLSQL 在变量中存储具有未知数据类型的游标(使用 FETCH INTO)

MySQL存储过程相关指令和函数集

在预期以下情况之一时遇到符号“INTO”

如何使用Oracle的游标?