2016-11-09 144 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及更高版本,您當前的代碼將按預期工作。

相關問題