2016-11-09 4 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

Ваша функция can not возвращает 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 etermining, который обработчик для выбора. Ранее сохраненная программа рассматривалась как имеющая единственную область для выбора обработчика.

Так что ваш NOT FOUND продолжать обработчик будет, к сожалению, будет вызван не находя строк в mapping_civility в функции, потому что вы использовали into там.

Вы можете повторно инициализировать переменную непосредственно перед тем, как выборки новых строк, чтобы сбросить все, что случилось раньше:

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

Если у вас есть вложенные циклы, как в исходном вопросе, следует помнить, что она по-прежнему будет только один (активный), поэтому используйте одну и ту же переменную для обеих петель и сбросьте ее перед каждым fetch.

Для MySQL 5.6 и выше ваш текущий код будет работать должным образом.

Смежные вопросы