I created a simple stored procedure that loops through rows of one table and inserts them into another. For some reason the END WHILE loop is throwing a missing semicolon error. All the code looked right to me, and all the delimiters were set up right. I just can't figure out why it would be throwing these errors, googling this problem only pointed me to improperly used delimiter answers, but nothing more. Any help would be nice!
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 ;
When I am stuck with a problem in a large block of code and can't find where the problem is, I usually split my code in smaller chunks and test them one at a time:
Test 1:
DELIMITER $$
DROP PROCEDURE IF EXISTS `testLoop`$$
CREATE PROCEDURE testLoop()
BEGIN
END $$
DELIMITER ;
No errors: procedure declaration and use of delimiters is OK.
Test 2:
DELIMITER $$
DROP PROCEDURE IF EXISTS `testLoop`$$
CREATE PROCEDURE `testLoop`()
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
END $$
DELIMITER ;
No errors: the declaration of variables within the procedure is OK.
Test 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 ;
No errors: the SELECT query and the variable assignment are OK.
Test 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 ;
No errors: the WHILE loop is OK.
Test 5:
The only untested part is now the INSERT query:
INSERT INTO `test_2` (sku, qty) VALUES(sku, qty) FROM `test_dropship_upload` LIMIT i,1;
Looking a the documentation for INSERT and INSERT ... SELECT, we can see that your query is not valid: it is apparently missing a SELECT part and shouldn't have a VALUES part if you want to insert values from another table:
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 ;
The procedure creation now completes without errors.
Test 6:
However, you will get a syntax error on the SELECT query when executing the procedure: MySQL doesn't accept using LIMIT with a variable.
To make it work, you need to use a 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:
Because local variables are in scope only during stored program
execution, references to them are not permitted in prepared statements
created within a stored program. Prepared statement scope is the
current session, not the stored program, so the statement could be
executed after the program ends, at which point the variables would no
longer be in scope. For example, SELECT ... INTO local_var cannot be
used as a prepared statement. This restriction also applies to stored
procedure and function parameters.
To circumvent this problem, use a session variable #i instead of your local variable i:
Final version of the procedure:
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 ;
You can apply the same method to debug many complex programming problems: start with a simple version of your code, test it. If it works test again with a more code, if not locate and fix the errors before continuing.
Related
I am trying to insert into a table by using a loop that looks at a view and inserts each row one by one, I am planning to add more conditions bust I cant get the procedure working.
This is what I have:
DROP PROCEDURE IF EXISTS looprow;
DELIMITER ;;
CREATE PROCEDURE looprow()
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
SELECT COUNT(*) FROM Ordered_Students INTO n;
SET i=0;
WHILE i<n DO
INSERT INTO Project_Assigned(StudentID, Project_Title) SELECT (StudentID, Rank1) FROM Ordered_Students LIMIT i,1;
SET i = i + 1;
END WHILE;
End;
;;
DELIMITER ;
CALL looprow();
And the view I'm taking from looks like this:
I am getting the error= 1241 operand should contain 1 column.
Thank you for your help.
The brackets SELECT (StudentID, Rank1) are the problem - remove them.
I don't get what is wrong with this script
BEGIN
DECLARE crs INT DEFAULT 0;
WHILE crs < 10 DO
INSERT INTO `continent`(`name`) VALUES ('cont'+crs)
SET crs = crs + 1;
END WHILE;
END;
I want it to insert 10 values into the table continent but there is an error at the second line.
declare variable in MySQL with # and assign with :=
SET #crs = 0; // declaration
--here your query
#crs := #crs+1 // assignment
References
user defined variables
assignment
MySQL does not support the execution of anonymous blocks of stored procedure code.
You need to create a stored procedure including that code and then invoke it.
Also, you were missing the semi-colon at the end of your insert statements. I fixed that. You also probably want to use concat() instead of + to generate the names, but I'll leave that change to you.
Create the procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS insert_ten_rows $$
CREATE PROCEDURE insert_ten_rows ()
BEGIN
DECLARE crs INT DEFAULT 0;
WHILE crs < 10 DO
INSERT INTO `continent`(`name`) VALUES ('cont'+crs);
SET crs = crs + 1;
END WHILE;
END $$
DELIMITER ;
Invoke the procedure:
CALL insert_ten_rows();
I am using a procedure to loop through a table and perform a different procedure on each row (this procedure uses other tables and works fine, returns correct result set). Here is my attempt:
DELIMITER $$
CREATE PROCEDURE user_loop()
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
SELECT COUNT(*) FROM users INTO n;
SET i=0;
WHILE i<n DO
SET #cur_id = (SELECT user_id from users LIMIT i,1);
INSERT INTO results CALL other_proc(#cur_id);
SET i = i + 1;
END WHILE;
End;
$$
Not sure what the correct syntax is in order to do this, I looked but couldn't find any examples.
I don't get what is wrong with this script
BEGIN
DECLARE crs INT DEFAULT 0;
WHILE crs < 10 DO
INSERT INTO `continent`(`name`) VALUES ('cont'+crs)
SET crs = crs + 1;
END WHILE;
END;
I want it to insert 10 values into the table continent but there is an error at the second line.
declare variable in MySQL with # and assign with :=
SET #crs = 0; // declaration
--here your query
#crs := #crs+1 // assignment
References
user defined variables
assignment
MySQL does not support the execution of anonymous blocks of stored procedure code.
You need to create a stored procedure including that code and then invoke it.
Also, you were missing the semi-colon at the end of your insert statements. I fixed that. You also probably want to use concat() instead of + to generate the names, but I'll leave that change to you.
Create the procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS insert_ten_rows $$
CREATE PROCEDURE insert_ten_rows ()
BEGIN
DECLARE crs INT DEFAULT 0;
WHILE crs < 10 DO
INSERT INTO `continent`(`name`) VALUES ('cont'+crs);
SET crs = crs + 1;
END WHILE;
END $$
DELIMITER ;
Invoke the procedure:
CALL insert_ten_rows();
I am running a stored procedure. The issue seems to be that it will go into the if statement. Also for some reason or another regardless of how many selects I use it will only return the first. I've copied this from another stored procedure that works like a charm, but this one just won't go. Any ideas?
DROP PROCEDURE IF EXISTS genSelPriceTier;
DELIMITER $$
CREATE PROCEDURE genSelPriceTier(tier_id INT, default_id INT)
BEGIN
DECLARE rowCount INT DEFAULT 0;
SELECT * FROM price_tier WHERE price_tier_id = tier_id;
SET rowCount = FOUND_ROWS();
IF rowCount < 1 THEN
SELECT * FROM price_tier WHERE price_tier_id = default_id;
END IF;
END$$
DELIMITER ;
There is a bug reported related to the usage of FOUND_ROWS(). So, I recommend using Count(*) for the number of rows returned. Something like the following should work.
DROP PROCEDURE IF EXISTS genSelPriceTier;
DELIMITER $$
CREATE PROCEDURE genSelPriceTier(tier_id INT, default_id INT)
BEGIN
DECLARE rowCount INT DEFAULT 0;
SELECT COUNT(*) INTO rowCount FROM price_tier WHERE price_tier_id = tier_id
IF rowCount < 1 THEN
SELECT * FROM price_tier WHERE price_tier_id = default_id;
END IF;
END$$
DELIMITER ;