【问题标题】:MySQL - Using SELECT INTO statement inside cursor in stored procedureMySQL - 在存储过程的游标内使用 SELECT INTO 语句
【发布时间】:2019-01-30 09:43:36
【问题描述】:

我正在使用游标在 MySQL 数据库中编写存储过程来迭代记录。我能够在 FETCH 语句中指定的变量内获取记录,但是当我在游标内使用 SELECT 时,我无法将结果存储在变量中。我知道它可能,但不知道为什么它不能在下面的 MySQL 代码中工作。

CREATE DEFINER=`root`@`localhost` PROCEDURE `add_monthly_leave_entitlement`
(IN `emp` INT(10), OUT `experience` INT(10), OUT `entitlement` DECIMAL(10,4)) DETERMINISTIC
BEGIN 

DECLARE emp_no INT(10);
DECLARE current_month_exp INT(10);
DECLARE previous_month_end_exp INT(10);
DECLARE emp_status INT(10);

DECLARE done INT DEFAULT FALSE;
DECLARE monthly_entitlement decimal(8,4) DEFAULT 0;

DECLARE emp_cursor CURSOR FOR
SELECT e.`emp_number` AS emp_no, 
TIMESTAMPDIFF( YEAR, e.`joined_date` , NOW( ) ) AS month_start_exp, 
TIMESTAMPDIFF( YEAR, e.`joined_date`, LAST_DAY(NOW()- INTERVAL 1 MONTH) ) AS last_month_end_exp, e.`emp_status` AS emp_status 
FROM `hs_hr_employee` AS e 
WHERE e.`termination_id` is null AND e.`emp_number`=emp;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

OPEN emp_cursor;

read_loop : LOOP
FETCH emp_cursor INTO emp_no, current_month_exp, previous_month_end_exp, emp_status;
    IF done THEN
        LEAVE read_loop;
    END IF;

    /*Monthly entitlement as per experience*/       
    SELECT `monthly_entitlement` INTO monthly_entitlement 
    FROM `ohrm_leave_entitlement_conf` 
    WHERE `year_completion` = IF(previous_month_end_exp >4 , 5, previous_month_end_exp) 
    AND `leave_type_id` = 4;

   SET experience = previous_month_end_exp;
   SET entitlement = monthly_entitlement;

END LOOP;

CLOSE emp_cursor;
END

无法在 monthly_entitlemententitlement 内获取值,该值始终为 0.0000。 我尝试在单独的过程中运行每月权利查询,它返回正确的值。我有匹配表列和变量的数据类型。

有人可以帮我理解这里有什么问题吗?

【问题讨论】:

  • 要调试它,在 if done..endif 语句之后添加一个 select 以显示从光标到局部变量的内容并从那里继续。顺便说一句,我会避免给局部变量赋予与表列相同的名称,并给它们一个前缀(例如 lv_)以澄清代码。

标签: mysql stored-procedures cursor


【解决方案1】:

避免将局部变量命名为列名,请参阅Chapter 2 Restrictions on Stored Programs :: Name Conflicts within Stored Routines。尝试更改以下内容:

...
-- DECLARE monthly_entitlement decimal(8,4) DEFAULT 0;
DECLARE _monthly_entitlement decimal(8,4) DEFAULT 0;
...
/*Monthly entitlement as per experience*/
-- SELECT `monthly_entitlement` INTO monthly_entitlement
SELECT `monthly_entitlement` INTO _monthly_entitlement
...
-- SET entitlement = monthly_entitlement;
SET entitlement = _monthly_entitlement;
...

【讨论】:

    【解决方案2】:

    根据其他人的建议,局部变量的名称和列名应该不同,所以这里的变化

    CREATE DEFINER=`root`@`localhost` PROCEDURE `add_monthly_leave_entitlement`
    (IN `emp` INT(10), OUT `experience` INT(10), OUT `entitlement` DECIMAL(10,4)) DETERMINISTIC
    BEGIN 
    
    DECLARE v_emp_no INT(10);
    DECLARE v_current_month_exp INT(10);
    DECLARE v_previous_month_end_exp INT(10);
    DECLARE v_emp_status INT(10);
    
    DECLARE done INT DEFAULT FALSE;
    DECLARE v_monthly_entitlement decimal(8,4) DEFAULT 0;
    
    DECLARE emp_cursor CURSOR FOR
    SELECT e.`emp_number` AS emp_no, 
    TIMESTAMPDIFF( YEAR, e.`joined_date` , NOW( ) ) AS month_start_exp, 
    TIMESTAMPDIFF( YEAR, e.`joined_date`, LAST_DAY(NOW()- INTERVAL 1 MONTH) ) AS last_month_end_exp, e.`emp_status` AS emp_status 
    FROM `hs_hr_employee` AS e 
    WHERE e.`termination_id` is null AND e.`emp_number`=emp;
    
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    
    OPEN emp_cursor;
    
    read_loop : LOOP
    FETCH emp_cursor INTO v_emp_no, v_current_month_exp, v_previous_month_end_exp, v_emp_status;
        IF done THEN
            LEAVE read_loop;
        END IF;
    
        /*Monthly entitlement as per experience*/       
        SELECT `monthly_entitlement` INTO v_monthly_entitlement 
        FROM `ohrm_leave_entitlement_conf` 
        WHERE `year_completion` = IF(v_previous_month_end_exp >4 , 5, v_previous_month_end_exp) 
        AND `leave_type_id` = 4;
    
       SET experience = v_previous_month_end_exp;
       SET entitlement = v_monthly_entitlement;
    
    END LOOP;
    
    CLOSE emp_cursor;
    END
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-11
      • 1970-01-01
      相关资源
      最近更新 更多