2016-11-09 61 views
2

我在写一个过程,它获取一个数据表以映射一个字段并在另一个表中插入/更新。MySQL过程的光标在第一次迭代后停止

我的问题是,如果映射函数没有找到任何匹配,我的光标将在第一次迭代后停止而不会引发任何错误。

这里是我的功能:

BEGIN 
    DECLARE mapped_name VARCHAR(255); 

    SELECT mapped_field INTO mapped_name 
     FROM mapping_civility 
     WHERE original_field = nameVar 
    LIMIT 1; 

    IF mapped_name IS NULL THEN 
     RETURN 'INDEFINI'; 
    ELSE 
     RETURN mapped_name; 
    END IF; 
END 

通过测试它,我发现,如果在我的映射表,它的工作原理相应的字段,但如果SELECT返回NULL值,因为没有映射场被发现,它会在第一次迭代时停止光标。

然后我尝试了另一个数据库,在另一台服务器上,一切都很顺利,所以也许配置有问题?两者都有字符集“latin1 - cp1252西欧”整理“latin1_swedish_ci”。

这里是我的程序代码:

BLOCK1: BEGIN 
    DECLARE no_more_rows1 INT; 
    DECLARE my_name VARCHAR(255); 
    DECLARE civility VARCHAR(255); 

    DECLARE curseur1 CURSOR FOR 
     SELECT `name` 
     FROM source; 

    DECLARE CONTINUE handler FOR NOT FOUND SET no_more_rows1 = TRUE; 

    OPEN curseur1; 
    LOOP1: LOOP 
     FETCH curseur1 INTO my_name; 
     IF no_more_rows1 THEN 
      CLOSE curseur1; 
      LEAVE LOOP1; 
     END IF; 

      SET civility = get_civility(my_name); 

      INSERT INTO log (id, message, date) VALUES (NULL, CONCAT(my_name, ' : ', civility), NOW()); 

    END LOOP LOOP1;  
END BLOCK1; 

此过程将正确插入如果名称以及映射,但如果名称不映射将在第一行后停止。

你可以用下面的表格

-- ---------------------------- 
-- Table structure for `source` 
-- ---------------------------- 
DROP TABLE IF EXISTS `source`; 
CREATE TABLE `source` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4; 

-- ---------------------------- 
-- Records of source 
-- ---------------------------- 
INSERT INTO `source` VALUES ('1', 'Pierre'); 
INSERT INTO `source` VALUES ('2', 'David'); 
INSERT INTO `source` VALUES ('3', 'Kevin'); 
INSERT INTO `source` VALUES ('4', 'Pierre'); 
INSERT INTO `source` VALUES ('5', 'Donald Pierre'); 


-- ---------------------------- 
-- Table structure for `log` 
-- ---------------------------- 
DROP TABLE IF EXISTS `log`; 
CREATE TABLE `log` (
    `id` int(5) NOT NULL AUTO_INCREMENT COMMENT 'id', 
    `message` text COMMENT 'message', 
    `date` varchar(64) DEFAULT NULL COMMENT 'date', 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


-- ---------------------------- 
-- Table structure for `mapping_civility` 
-- ---------------------------- 
DROP TABLE IF EXISTS `mapping_civility`; 
CREATE TABLE `mapping_civility` (
    `id` int(5) NOT NULL AUTO_INCREMENT COMMENT 'id', 
    `original_field` varchar(255) DEFAULT NULL COMMENT 'original_field', 
    `mapped_field` varchar(255) DEFAULT NULL COMMENT 'mapped_field', 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; 

-- ---------------------------- 
-- Records of mapping_civility 
-- ---------------------------- 
INSERT INTO `mapping_civility` VALUES ('1', 'kevin', 'H'); 
INSERT INTO `mapping_civility` VALUES ('2', 'pierre', 'H'); 
INSERT INTO `mapping_civility` VALUES ('3', 'isabelle', 'F'); 
+0

您的函数不能'返回NULL,而是字符串'INDEFINI'。那么,为什么当函数返回NULL时程序停止? –

+0

因此,代码在一台服务器上工作,而不是另一台服务器上?我发现你的代码很难遵循,试着将代码减少到一个最小的例子,也许有一些示例数据和表结构,可以重现你的错误。没有人想研究代码1小时以了解它的功能。但是快速遍历你的代码让我怀疑没有初始化'no_more_rows2',在第一次循环之后它将是真的,并且永远不会再次到达插入阶段。 (与'no_more_rows1'相同,尽管它看起来没有效果)。听起来像你所描述的(除了'null'部分)。 – Solarflare

+0

@ThomasG你是完全正确的,我修改我的函数添加IF mapped_ratecode IS NULL语句,同时做一些测试,我会修改我的问题 – Kvn91

回答

2

的MySQL 5.6之前,存储过程只有一个处理器进行测试,看changelogs for 5.6

此外,在条件处理程序处理规则的几个不足之处进行了更正,以便MySQL的行为更像是标准SQL:

  • 块范围用于d确定选择哪个处理程序。以前,存储的程序被视为具有用于处理程序选择的单个作用域。

所以你NOT FOUND继续处理程序将不幸被你的函数没有找到在mapping_civility行被触发,因为你使用into那里。

您可以重新初始化你获取新行重置一切直接之前变量之前已经happend:

... 
LOOP1: LOOP 
    set no_more_rows1 = false; -- add this 
    FETCH curseur1 INTO my_name; 
    IF no_more_rows1 THEN 
... 

如果你已经在你原来的问题嵌套循环一样,要知道,它仍然只是一个(活动)处理程序,因此在两个循环中使用相同的变量并在每个fetch之前重置它。

对于MySQL 5.6及更高版本,您当前的代码将按预期工作。

相关问题