Когда я застрял с проблемой в большом блоке кода и не может найти, где проблема, я обычно разделить свой код на более мелкие куски и протестировать их по одному за раз:
Тест 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 ;
Вы можете применить тот же метод для отладки многие сложные проблемы программирования: начните с простой версии вашего кода, протестируйте его. Если он снова проверяет работу с большим количеством кода, если не обнаруживать и исправлять ошибки перед продолжением.
Полностью посмотрел, что, спасибо за помощь, все хорошо –