我创建了一个简单的存储过程,它循环遍历一个表的行并将它们插入另一个表中。由于某种原因,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 ;
答案 0 :(得分: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
部分,不应该有{{1如果要从另一个表中插入值,则部分:
VALUES
现在,程序创建完成且没有错误。
测试6:
但是,执行该过程时,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 ;
查询会出现语法错误:MySQL不接受将SELECT
与变量一起使用。
要使其工作,您需要使用prepared statement。
LIMIT
It is also not allowed to used local variables in prepared statements:
因为局部变量仅在存储程序期间在范围内 执行,准备好的陈述中不允许引用它们 在存储的程序中创建。准备好的声明范围是 当前会话,而不是存储的程序,所以声明可以 程序结束后执行,此时变量不会 更长的范围。例如,SELECT ... INTO local_var不能 用作准备好的声明。此限制也适用于存储 程序和功能参数。
要解决此问题,请使用会话变量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;
而不是本地变量@i
:
程序的最终版本:
i
您可以应用相同的方法来调试许多复杂的编程问题:从简单版本的代码开始,对其进行测试。如果它再次使用更多代码进行测试,如果没有在继续之前找到并修复错误。