Mysql syntax error on stored procedure - mysql

I run this code as a sql script from command line, and I get "you have an error in your SQL syntax" almost in all lines! Any ideas what is wrong here?
CREATE PROCEDURE updatemandate()
BEGIN
DECLARE _mandate_id BIGINT(20);
DECLARE _has_succesful_payment tinyint(1);
DECLARE done INT DEFAULT 0;
DECLARE cnt INT;
DECLARE mandateCursor CURSOR FOR Select mandate_id, has_succesful_payment From mandates;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN mandateCursor;
allmandates: LOOP
Fetch mandateCursor INTO _mandate_id, _has_succesful_payment;
IF done THEN LEAVE allmandates;
END IF;
Select COUNT(*) FROM payments WHERE mandate_id=_mandate_id AND status='OK' into cnt;
IF cnt>0 THEN
SET _has_succesful_payment=1;
END IF;
END LOOP allmandates;
CLOSE mandateCursor;
END

The ; character is the default delimiter, so when MySQL sees the first ; it thinks you are done. When you create a sproc, you need to declare a different delimiter character, like so:
DELIMITER $$
CREATE PROCEDURE updatemandate()
READS SQL DATA
BEGIN
DECLARE _mandate_id BIGINT(20);
DECLARE _has_succesful_payment tinyint(1);
DECLARE done INT DEFAULT 0;
DECLARE cnt INT;
DECLARE mandateCursor CURSOR FOR Select mandate_id, has_succesful_payment From mandates;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN mandateCursor;
allmandates: LOOP
Fetch mandateCursor INTO _mandate_id, _has_succesful_payment;
IF done THEN LEAVE allmandates;
END IF;
Select COUNT(*) FROM payment WHERE mandate_id=_mandate_id AND status='OK' into cnt;
IF cnt>0 THEN
SET _has_succesful_payment=1;
END IF;
END LOOP allmandates;
CLOSE mandateCursor;
END$$
DELIMITER ;
Also a good idea to add the READS SQL DATA to the sproc definition in case you need to support binary logging.

Have you tried putting delimiter // before the CREATE statement and change the last line with END //?

Related

Handling unfound data in mySQL procedure loop

I think I'm narrowing in on my issue. I have a loop that is only firing once:
DELIMITER $$
DROP PROCEDURE IF EXISTS `thread_updates` $$
CREATE PROCEDURE `thread_updates`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE my_curr_id INT DEFAULT NULL;
-- DECLARE other vars
DECLARE fixer_cursor CURSOR FOR
SELECT DISTINCT(id)
FROM log
WHERE date >= '2018-01-01';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN fixer_cursor;
REPEAT
FETCH fixer_cursor INTO my_curr_id;
IF NOT done THEN
SELECT data FROM table WHERE id = my_curr_id; -- This may not exist
-- Do other stuff with 'data' or NULL from above
END IF;
UNTIL done END REPEAT;
CLOSE fixer_cursor;
END $$
DELIMITER ;
I think the issue may be that inside the IF NOT done THEN loop, I have a few select statements that may be trying to select results that don't exist (not found).
This is fine (for me) as the logic continues along using NULL values in those spots, but I suspect that my CONTINUE HANDLER FOR NOT FOUND is catching the NOT FOUND warning that these selects throw inside the loop and are thus stopping the entire loop prematurely.
How can I listen for NOT FOUND warning on my cursor only?
Or, how can I suppress the NOT FOUND warning in my MAYBE FOUND select statements inside my loop so my loop continues?
I think I have solved the issue by implementing a counter in a loop rather than relying on the NOT FOUND handler:
DELIMITER $$
DROP PROCEDURE IF EXISTS `thread_updates` $$
CREATE PROCEDURE `thread_updates`()
BEGIN
DECLARE my_total INT DEFAULT NULL; -- Declare total
DECLARE my_counter INT DEFAULT 0; -- Declare counter starting at 0
DECLARE my_curr_id INT DEFAULT NULL;
-- DECLARE other vars
DECLARE fixer_cursor CURSOR FOR
SELECT DISTINCT(id)
FROM log
WHERE date >= '2018-01-01';
OPEN fixer_cursor;
SELECT FOUND_ROWS() INTO my_total; -- Get total number of rows
my_fixerloop: LOOP
FETCH fixer_cursor INTO my_curr_id;
IF my_counter >= my_total THEN -- Compare counter to total
CLOSE fixer_cursor;
LEAVE my_fixerloop;
END IF;
SET my_counter = my_counter + 1; -- Increment by one for each record
SELECT data FROM table WHERE id = my_curr_id; -- This may not exist
-- Do other stuff with 'data' or NULL from above
END LOOP;
END $$
DELIMITER ;

what is wrong in this mysql cursor, and how to correct it?

CREATE PROCEDURE curLike()
BEGIN
DECLARE likeRec likecounttable;
DECLARE c_likeCount CURSOR FOR SELECT l.likeCount, l.qId FROM likecounttable l;
OPEN c_likeCount;
start_loop:LOOP
FETCH c_likeCount IN likeRec
UPDATE qentry SET qentry.likeCount = likeRec.likeCount WHERE qentry.qId=likeRec.qId;
END LOOP;
CLOSE c_likeCount;
END;
I am trying to use a cursor here which fetches records from likecounttable, I saw this type of syntax in few sites so I used it but it is not working
You are missing a semi-colon after your first declaration, furthermore, likecounttable is a table, not a data type.
Since you're trying to store two column values into your declared variables, your first line should look more like this
DECLARE likeRec_Count, likeRec_qId INT;
After reading your code, if you aren't adding to your cursor, you can simplify by using the following sql instead, which does the same thing as your cursor.
UPDATE qentry JOIN likecounttable l ON l.qId=qentry.qId
SET qentry.likeCount = l.likeCount
;
EDIT: If you wanted a complete update to your cursor, the following should do the same thing.
DELIMITER $$
CREATE PROCEDURE curLike()
BEGIN
DECLARE c_likeRec_isdone BOOLEAN DEFAULT FALSE;
DECLARE likeRec_Count, likeRec_qId INT;
DECLARE c_likeCount CURSOR FOR SELECT l.likeCount, l.qId FROM likecounttable l;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET c_likeRec_isdone = TRUE;
OPEN c_likeCount;
loop_likeRecList: LOOP
FETCH c_likeCount INTO likeRec_Count, likeRec_qId;
IF c_likeRec_isdone THEN
SET c_likeRec_isdone = FALSE;
LEAVE loop_likeRecList;
END IF;
UPDATE qentry SET qentry.likeCount = likeRec_Count WHERE qentry.qId=likeRec_qId;
END LOOP loop_likeRecList;
CLOSE c_likeCount;
END;
$$
CREATE PROCEDURE curLike()
BEGIN
DECLARE likeRec_Count, likeRec_qId INT;
DECLARE c_likeCount CURSOR FOR SELECT l.likeCount, l.qId FROM likecounttable l;
OPEN c_likeCount;
start_loop:LOOP
FETCH c_likeCount INTO likeRec_Count,likeRec_qId
UPDATE qentry SET qentry.likeCount = likeRec_Count WHERE qentry.qId=likeRec_qId ;
END LOOP;
CLOSE c_likeCount;
END;

Cursor incorrect integer value error

I am trying to make my first cursor in MySQL and I am receiving an error. It says incorrect integer value. I was thinking this would grab the value in row one from column customer_Id, and store it into the IdValue variable. How do I code this correctly and fix this error?
DELIMITER $$
CREATE PROCEDURE CursorProcedure()
BEGIN
DECLARE IdValue int;
DECLARE myCursor CURSOR FOR
SELECT customer_Id FROM customers;
OPEN myCursor;
FETCH myCursor INTO IdValue;
CLOSE myCursor;
SELECT IdValue;
END$$
DELIMITER ;
DROP PROCEDURE IF EXISTS CursorProcedure;
DELIMITER $$
CREATE PROCEDURE CursorProcedure()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE IdValue int;
DECLARE myCursor CURSOR FOR SELECT customer_Id FROM customers;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN myCursor;
read_loop: LOOP
FETCH myCursor INTO IdValue;
IF done THEN
LEAVE read_loop;
END IF;
--
-- YOU ARE IN YOUR READ LOOP
-- DO SOMETHING WITH IT HERE
--
END LOOP;
CLOSE myCursor;
END$$
DELIMITER ;
But in the "do something with it here", don't do a SELECT on it because it will generate multiple result sets. Do something meaningful.
Manual page on Cursors.
As an aside, cursors are rarely your friends. They are extremely slow. Use them in dire emergencies only.

Errors declaring variables in stored procedure?

I'm sort of new to SQL and stored procedures. I'm trying to set some variables to use later on in a transaction while also setting a rollback variable on an exception, but I'm not able to do this.
I don't know where the error is because when I switch the how_many section after the _rollback, The error changes.
What's wrong with the way I'm declaring variables here?
DELIMITER $$
DROP PROCEDURE IF EXISTS `do_thing` $$
CREATE PROCEDURE `do_thing`()
BEGIN
DECLARE how_many INT;
SELECT COUNT(*) FROM things INTO how_many;
-- Prepare roleback.
DECLARE `_rollback` BOOL DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET `_rollback` = 1;
-- Start transaction.
START TRANSACTION;
-- Do all the things.
IF `_rollback` THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
END $$
DELIMITER ;
EDIT:
when I declare variables like this:
DECLARE how_many INT;
-- Prepare roleback.
DECLARE `_rollback` BOOL DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET `_rollback` = 1;
SELECT COUNT(*) FROM tiers INTO how_many;
It seems to be fine. Am I not allowed to declare more variables after certain variables in a procedure are set?
From the Manual Page DECLARE Syntax:
DECLARE is permitted only inside a BEGIN ... END compound statement
and must be at its start, before any other statements.
Declarations must follow a certain order. Cursor declarations must appear before handler declarations. Variable and condition
declarations must appear before cursor or handler declarations.
Note that these are called Local Variables in mysql. These differ from User Variables (prefixed with the # symbol), which can be sprinkled about with your statements and do not require a DECLARE.
The DECLARE statements are only permitted after BEGIN, if you try to add another DECLARE after that it shows error.
Move the line SELECT COUNT(*) FROM things INTO how_many; after all DECLARE lines.
DELIMITER $$
DROP PROCEDURE IF EXISTS `do_thing` $$
CREATE PROCEDURE `do_thing`()
BEGIN
DECLARE how_many INT;
-- Prepare roleback.
DECLARE `_rollback` BOOL DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET `_rollback` = 1;
-- Start transaction.
START TRANSACTION;
SELECT COUNT(*) FROM things INTO how_many;
-- Do all the things.
IF `_rollback` THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
END $$
DELIMITER ;

mysql stored procedure variable error

Hi I am finding my way round MySQL trying to migrate data from MSsql for the first time. I have created a stored procedure that clear all the tables down so I can import the data repeatedly as I test and alter things. I thought I had this pretty well figured but I am unsure how to get the actual value of the variable to go with the delete statement. Thanks for any assistance
DELIMITER $$
CREATE PROCEDURE ClearData ()
BEGIN
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_TableName varchar(100) DEFAULT "";
-- declare cursor for list of tables to clear
DEClARE TableToRemove CURSOR FOR
SELECT TABLE_NAME from information_schema.tables where table_type ='BASE TABLE';
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;
OPEN TableToRemove;
ClearData: LOOP
FETCH TableToRemove INTO v_TableName;
IF v_finished = 1 THEN
LEAVE ClearData;
END IF;
--This is the problem how do I get the value of v_TableName
delete from `v_TableName`;
END LOOP ClearData;
CLOSE TableToRemove;
END$$
DELIMITER ;