for each loop in trigger - mysql

Unable to use for each loop in trigger
I am getting
Error Code: 1064
DELIMITER $$
CREATE
TRIGGER `TRG_AU_DEVICES_HOWLONG` AFTER UPDATE ON `devices`
FOR EACH ROW BEGIN
DECLARE lastid INTEGER;
DECLARE a, b, c VARCHAR(255);
SET #lastid := (SELECT deviceId FROM devices ORDER BY packetDate DESC LIMIT 1);
DECLARE cur1 CURSOR FOR SELECT alertType,deviceId FROM alerts WHERE alerts.deviceId = #lastid ;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO a, b;
insert into test(alertType,deviceId) values(a,b);
END LOOP;
CLOSE cur1;
END;
$$
DELIMITER ;
Unable to use for each loop in trigger, am getting Error Code: 1064.How to use for each loop in trigger

DELIMITER $$
CREATE
TRIGGER TRG_TEST BEFORE UPDATE ON devices
FOR EACH ROW BEGIN
DECLARE done INT DEFAULT 0;
DECLARE alert VARCHAR(255);
DECLARE my_cur CURSOR FOR SELECT alertType FROM alerts WHERE deviceId = 8170610948;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN my_cur;
my_cur_loop:
LOOP FETCH my_cur INTO a;
IF done = 1 THEN
LEAVE my_cur_loop;
END IF;
INSERT INTO test (alertType)VALUES(alert);
END LOOP my_cur_loop;
CLOSE my_cur;
END;
$$

You are referencing your own looped array inside the array. I call this a loop bomb.
Since you expect the statement inside the loop to return control to the loop, but the flow of logic can not reversed halfway through a loop mechanically.It can be conditioned, not reversed because the array is not expressed, it is defined.
To Achieve logical expression of the array before the construct, consider using, predefined data matrices, lambda functions or Using Lambda programming that includes meta or reflective paradigms. Lisp, GUILE, OCAMEL are examples.

Related

Nested Cursor Into Mysql

I am creating cursor within cursor and first cursor getting unique value and second cursor is generating details number of rows. I found second cursor is running one time and not populating rows against every row id. Please guide
DELIMITER $$
USE `dum_data`$$
DROP PROCEDURE IF EXISTS `sp_process_gen`$$
CREATE DEFINER=`test`#`%` PROCEDURE `sp_process_gen`()
BEGIN
DECLARE cur1_done,cur2_done INT DEFAULT 0;
DECLARE v_thread_id, v_id,v_tab,v_event_time INT;
DECLARE v_stime,v_etime DATETIME;
-- declaring cursor
DECLARE cur1 CURSOR FOR
SELECT thread_id
FROM general_log
-- WHERE thread_id in (306710429,306711335)
GROUP BY thread_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET cur1_done = 1;
OPEN cur1;
cur1_loop: LOOP
FETCH cur1 INTO v_thread_id;
-- INSERT INTO aa VALUES(NULL,v_thread_id,NULL,NULL);
block2: BEGIN
DECLARE cur2 CURSOR FOR
SELECT id , event_time
FROM general_log
WHERE thread_id = v_thread_id
ORDER BY id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET cur2_done = 1;
OPEN cur2;
cur2_loop: LOOP
FETCH cur2 INTO v_id,v_stime;
IF cur2_done THEN
-- set cur1_done = 0;
CLOSE cur2;
LEAVE cur2_loop;
END IF;
-- INSERT INTO aa VALUES(v_id,v_thread_id,v_stime,v_stime);
INSERT INTO aa(thread_id) VALUES(v_thread_id);
-- FETCH cur2 INTO v_id,v_stime;
END LOOP cur2_loop;
END block2;
IF cur1_done THEN
CLOSE cur1;
LEAVE cur1_loop;
END IF;
INSERT INTO aa(thread_id) VALUES(999999);
-- FETCH cur1 INTO v_thread_id;
END LOOP cur1_loop;
-- CLOSE cur;
END$$
DELIMITER ;
I suspect your problem is the two CONTINUE HANDLER FOR NOT FOUND structures.
The second cursor will get it's first NOT FOUND at the end its loop, trigger both handlers... causing both loops to exit.
The way around this is to have a second stored procedure that contains the inner loop, and call that procedure from the outer loop. That way your handlers are in separate contexts.

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 ;

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.

MySQL procedure loop stops after one iteration

I am working on a MySQL procedure that creates a summary of one of my tables. The procedure retrieves a dataset and loops through it using a cursor. For each iteration of the loop, the procedure updates another table. The problem I'm having is the loop ends after a single iteration, event though I know that the query I'm running retrieves more than one row.
BEGIN
# Variable declaration section omitted for brevity
DECLARE cur CURSOR FOR SELECT
t.result_id,
t.athlete_id, t.`first`, t.middle, `last`, t.pref, t.birth,t.uss,
t.club_id,t.code,t.club_name,
t.meet_name,t.meet_id,t.`start`,t.`end`,
MIN(t.time) as time,t.age,t.type
FROM sometable t GROUP BY club_id ORDER BY time asc,t.start desc,club_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
read_loop: LOOP
FETCH cur INTO result_id,athlete_id, first_name, middle, last_name, pref, birth,uss,
club_id,club_code,club_name,
meet_name,meet_id,start_date,end_date,
result_time,age,type;
IF done=1 THEN
LEAVE read_loop;
END IF;
SET last_time = result_time;
INSERT INTO toptimes(`result_id`,`club_id`,`agegroup`,`sex`,`distance`,`course`,`stroke`,`data`,`published`)
VALUES(result_id,club_id,AgeGroupID,sex,distance,course,stroke,json,0);
END LOOP read_loop;
CLOSE cur;
END
I'm not clear what the problem is. When I run the select query manually, I get back several rows. Is there a problem running an insert statement inside the loop?
Your code chunk looks good to me.
How do you know that it's running only one iteration (i'm not seeing any
print or select statement for debug purpose)?
Are you getting any error while executing the stored procedure?
I tried to replicate the similar code with "sakila" database (mysql sample db). It's working perfectly. Please check this sql code sample, if it helps you.
DROP PROCEDURE IF EXISTS usp_select_dummy_data ;
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE usp_select_dummy_data()
BEGIN
-- Declare your variables
Declare _var_actor_id int default 0;
DECLARE _var_film_id int default 0;
-- Declare variable used for cursor and loop control
DECLARE done int;
DECLARE loop_counter INT DEFAULT 0;
-- Declare the cursor
DECLARE cur CURSOR FOR
SELECT
actor_id, film_id
FROM film_actor;
-- Declare handlers
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-- Open the cursor
OPEN cur ;
-- Start the loop
read_loop: LOOP
FETCH cur
INTO _var_actor_id, _var_film_id ;
-- break out of the loop if
-- 1. if there is no rows or
-- 2. we've processed them all
IF done = 1 THEN
CLOSE cur ;
LEAVE read_loop ;
END IF;
-- Count the number of times looped
SET loop_counter = loop_counter + 1 ;
END LOOP read_loop ;
-- print the loop count
select loop_counter;
END

Printing out multiple rows in stored procedure

I want to pass in an int value and get back a list of short passwords that are less than this int. I have had trouble modifying the MySQL cursors example: http://dev.mysql.com/doc/refman/5.0/en/cursors.html. I want to print out the rows with short passwords but any time the result has more than one row PhpMyAdmin just displays "Processing request" indefinitely. What am I doing wrong? Its ruining my Saturday productivity!
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `ShortPasswd`(IN `passwordLength` TINYINT)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE a INT;
DECLARE b VARCHAR(255);
DECLARE cur1 CURSOR FOR SELECT UID, Password
FROM authentication WHERE CHARACTER_length(Password) < passwordLength;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO a, b;
IF done THEN
LEAVE read_loop;
END IF;
SELECT b;
END LOOP;
CLOSE cur1;
END
$$
DELIMITER ;
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `ShortPasswd`(IN `passwordLength` TINYINT)
BEGIN
SELECT UID, Password
FROM authentication WHERE CHARACTER_length(Password) > passwordLength;
END
$$
DELIMITER ;
You will get rows UID, password directly. as you get from a query when you
call ShortPasswd;
I suggest to modify these lines:
...
DECLARE FINISHED BOOLEAN DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
...
IF done THEN
CLOSE cur1;
LEAVE read_loop;
END IF;
...
END LOOP read_loop;
I use the 0/1 instead of FALSE/TRUE, and close the cursor before leave the LOOP.