2016-07-21 2 views
0

Я создал простую хранимую процедуру, которая пересекает строки одной таблицы и вставляет их в другую. По какой-то причине цикл END WHILE бросает недостающую точку с запятой. Весь код выглядел правильно, и все разделители были настроены правильно. Я просто не могу понять, почему это было бы выбросить эти ошибки, при этом эта проблема только указывала на неправильные ответы на разделители, но не более того. Любая помощь будет приятной!Завершить цикл с точкой с запятой

USE test; 
DELIMITER $$ 

DROP PROCEDURE IF EXISTS `testLoop`$$ 

CREATE PROCEDURE `testLoop`() 
BEGIN 
DECLARE n INT DEFAULT 0; 
DECLARE i INT DEFAULT 0; 
SELECT COUNT(*) FROM `test_dropship_upload` INTO n; 
SET i=0; 
WHILE i<n DO 
    INSERT INTO `test_2` (sku, qty) VALUES(sku, qty) FROM `test_dropship_upload` LIMIT i,1; 
    SET i = i + 1; 
END WHILE; 

END $$ 

DELIMITER ; 

ответ

1

Когда я застрял с проблемой в большом блоке кода и не может найти, где проблема, я обычно разделить свой код на более мелкие куски и протестировать их по одному за раз:

Тест 1:

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `testLoop`$$ 

CREATE PROCEDURE testLoop() 
BEGIN 
END $$ 

DELIMITER ; 

нет ошибок: порядок декларирования и использование разделителей в порядке.

Тест 2:

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `testLoop`$$ 

CREATE PROCEDURE `testLoop`() 
BEGIN 
DECLARE n INT DEFAULT 0; 
DECLARE i INT DEFAULT 0; 
END $$ 

DELIMITER ; 

Нет ошибок: декларация переменных в процедуре в порядке.

Тест 3:

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `testLoop`$$ 

CREATE PROCEDURE `testLoop`() 
BEGIN 
DECLARE n INT DEFAULT 0; 
DECLARE i INT DEFAULT 0; 
SELECT COUNT(*) FROM `test_dropship_upload` INTO n; 
SET i=0; 
END $$ 

DELIMITER ; 

Нет Ошибки: SELECT запрос и присвоение переменной ОК.

Тест 4:

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `testLoop`$$ 

CREATE PROCEDURE `testLoop`() 
BEGIN 
DECLARE n INT DEFAULT 0; 
DECLARE i INT DEFAULT 0; 
SELECT COUNT(*) FROM `test_dropship_upload` INTO n; 
SET i=0; 
WHILE i<n DO 
    SET i = i + 1; 
END WHILE; 

END $$ 

DELIMITER ; 

Нет ошибок: петля WHILE ОК.

Тест 5:

только непроверенная часть теперь INSERT запрос:

INSERT INTO `test_2` (sku, qty) VALUES(sku, qty) FROM `test_dropship_upload` LIMIT i,1; 

Глядя документацию для INSERT и INSERT ... SELECT, мы можем видеть, что ваш запрос не является действительным: он по-видимому, отсутствует часть SELECT и не должна содержать VALUES, если вы хотите вставить значения из другой таблицы:

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `testLoop`$$ 

CREATE PROCEDURE `testLoop`() 
BEGIN 
DECLARE n INT DEFAULT 0; 
DECLARE i INT DEFAULT 0; 
SELECT COUNT(*) FROM `test_dropship_upload` INTO n; 
SET i=0; 
WHILE i<n DO 
    INSERT INTO `test_2` (sku, qty) SELECT sku, qty FROM `test_dropship_upload` LIMIT i, 1; 
    SET i = i + 1; 
END WHILE; 

END $$ 

DELIMITER ; 

Создание процедуры теперь завершается без ошибок.

Тест 6:

Однако, вы получите синтаксическую ошибку на SELECT запроса при выполнении процедуры: MySQL не принимает с помощью LIMIT с переменной.
Чтобы заставить его работать, вам необходимо использовать prepared statement.

PREPARE stmt FROM "INSERT INTO `test_2` (sku, qty) SELECT sku, qty FROM `test_dropship_upload` LIMIT ?, 1"; 
EXECUTE stmt using @i; 
DEALLOCATE PREPARE stmt; 

It is also not allowed to used local variables in prepared statements:

Поскольку локальные переменные в области видимости только во время выполнения хранимой программы , ссылки на них не допускаются в подготовленных заявлений , созданных в рамках хранимой программы. Подготовленная область отчета представляет собой текущую сессию , а не сохраненную программу, поэтому оператор может быть , выполненный после завершения программы, после чего переменные не будут содержать . Например, SELECT ... INTO local_var не может быть , используемый в качестве подготовленного оператора. Это ограничение также относится к сохраненным параметрам процедуры и функции .

Чтобы обойти эту проблему, используйте переменную @i сеанса вместо вашей локальной переменной i:

Окончательный вариант процедуры:

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `testLoop`$$ 

CREATE PROCEDURE `testLoop`() 
BEGIN 
DECLARE n INT DEFAULT 0; 
SELECT COUNT(*) FROM `test_dropship_upload` INTO n; 
SET @i=0; 
WHILE @i<n DO 
    PREPARE stmt FROM "INSERT INTO `test_2`(sku, qty) SELECT sku, qty FROM `test_dropship_upload` LIMIT ?, 1"; 
    EXECUTE stmt USING @i; 
    DEALLOCATE PREPARE stmt; 
    SET @i = @i + 1; 
END WHILE; 

END $$ 

DELIMITER ; 

Вы можете применить тот же метод для отладки многие сложные проблемы программирования: начните с простой версии вашего кода, протестируйте его. Если он снова проверяет работу с большим количеством кода, если не обнаруживать и исправлять ошибки перед продолжением.

+0

Полностью посмотрел, что, спасибо за помощь, все хорошо –

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