I have this stored procedure in mysql:
DELIMITER $$
CREATE PROCEDURE createCompany ()
BEGIN
DECLARE finished INTEGER DEFAULT 0;
DECLARE company varchar(5000) DEFAULT "";
DEClARE cur CURSOR FOR SELECT company FROM companies;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1
OPEN cur;
getCompany: LOOP
FETCH cur INTO company;
IF finished = 1 THEN
LEAVE getCompany;
END IF;
call LOG(company);
END LOOP getCompany;
CLOSE cur;
END$$
DELIMITER ;
LOG procedure is:
DELIMITER $$
CREATE PROCEDURE `LOG`(IN message varchar(5000))
BEGIN
insert into tmplog (log) values (message);
END$$
DELIMITER ;
I have a temporal table called tmplog with two fields: date and log (varchar(5000))
When I call createCompany I get the next result:
the log column is empty... what is wrong?
Having variables with the same name as columns is very dangerous. Try this:
BEGIN
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_company varchar(5000) DEFAULT "";
DEClARE cur CURSOR FOR SELECT c.company FROM companies c;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = 1
OPEN cur;
getCompany: LOOP
FETCH cur INTO v_company;
IF v_finished = 1 THEN
LEAVE getCompany;
END IF;
call LOG(v_company);
END LOOP getCompany;
CLOSE cur;
END$$
DELIMITER ;
Related
I am trying a sample SP. This SP does not loop. Trying to figure what where the problem is. Any help is appreciated
DELIMITER $$
USE `DB`$$
DROP PROCEDURE IF EXISTS `build_email_list`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `build_email_list`()
BEGIN
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_email VARCHAR(100) DEFAULT "";
-- declare cursor for employee email
DECLARE email_cursor CURSOR FOR SELECT `email` FROM `people`;
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;
OPEN email_cursor;
get_email: LOOP
FETCH email_cursor
INTO v_email;
IF v_finished = 1 THEN
LEAVE get_email;
END IF;
-- print list
SELECT v_email;
END LOOP get_email;
CLOSE email_cursor;
END$$
DELIMITER ;
This is my current trigger:
DELIMITER $$
CREATE DEFINER=`root`#`127.0.0.1` TRIGGER `unique_visit_new_campaign` AFTER INSERT ON `unique_visit` FOR EACH ROW
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE pixel_id int;
DECLARE campaign_id varchar(45);
DECLARE cur CURSOR FOR SELECT id FROM pixels;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
ins_loop: LOOP
FETCH cur INTO pixel_id;
IF done THEN
LEAVE ins_loop;
END IF;
INSERT IGNORE INTO pixels_campaign (campaign_id , pixel_id , date) VALUES (NEW.campaign_id ,pixel_id, current_timestamp);
END LOOP;
CLOSE cur;
END
I need it to NOT TRIGGER when new.campaign_id is empty or equals to the string {campaign_id}
I tried using MySQL IF but with no success.
Also, It kinda auto increment even when there is a campaign id already (when it ignores). any way I can stop that from happening?
Did you try this?
DELIMITER $$
CREATE DEFINER=`root`#`127.0.0.1` TRIGGER `unique_visit_new_campaign` AFTER INSERT ON `unique_visit` FOR EACH ROW
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE pixel_id int;
DECLARE campaign_id varchar(45);
DECLARE cur CURSOR FOR SELECT id FROM pixels;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
IF new.campaign = '' or new.campaign = '{campaign_id}' or new.campaign is null THEN
OPEN cur;
ins_loop: LOOP
FETCH cur INTO pixel_id;
IF done THEN
LEAVE ins_loop;
END IF;
INSERT IGNORE INTO pixels_campaign (campaign_id , pixel_id , date) VALUES (NEW.campaign_id ,pixel_id, current_timestamp);
END LOOP;
CLOSE cur;
END IF
END
I added a trigger to my mysql database, but when it is used it doesn't terminate. What am I doing wrong?
My query to add the trigger:
DROP TRIGGER IF EXISTS insertResVals;
DELIMITER $$
create trigger insertResVals
AFTER INSERT
ON lastAccess
for each row begin
DECLARE done INT;
DECLARE res varchar(50);
DECLARE val double;
DECLARE sig VARCHAR(140);
DECLARE cur1 CURSOR FOR SELECT resource, value FROM resourceDefault;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
OPEN cur1;
SET done = 0;
read_loop: LOOP
FETCH cur1 INTO res, val;
IF NOT done THEN
LEAVE read_loop;
END IF;
insert into log
select concat(NEW.playerID, ", ", res, ", ", val);
if res<>null and val<>null THEN
INSERT INTO resourceValue VALUES(NEW.playerID, res, val);
ELSE
set done = 1;
END IF;
END LOOP;
CLOSE cur1;
END $$
DELIMITER ;
Thank you very much
I tried debugging, but the inserting into the log table did not work (I guess because the transaction is never finished).
The problem must be in the following line of code:
...
if res<>null and val<>null THEN
...
as this will always be NULL, and evaluates to FALSE.
Change the 12.3.2. Comparison Functions and Operators <> by IS NOT NULL:
...
IF res IS NOT NULL AND val IS NOT NULL THEN
...
UPDATE
The following trigger works without problem:
/* CODE FOR DEMONSTRATION PURPOSES */
/* Trigger structure for table `lastaccess` */
DROP TRIGGER IF EXISTS `insertResVals`;
DELIMITER $$
CREATE TRIGGER `insertResVals` AFTER INSERT ON `lastaccess`
FOR EACH ROW
BEGIN
DECLARE done INT default 0;
DECLARE res varchar(50);
DECLARE val double;
DECLARE sig VARCHAR(140);
DECLARE cur1 CURSOR FOR SELECT resource, value FROM resourcedefault;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
OPEN cur1;
SET done = 0;
read_loop: LOOP
FETCH cur1 INTO res, val;
IF done THEN
LEAVE read_loop;
END IF;
insert into log
select concat(NEW.playerid, ", ", res, ", ", val);
if res IS NOT null and val IS NOT null THEN
INSERT INTO resourcevalue VALUES(NEW.playerid, res, val);
ELSE
set done = 1;
END IF;
END LOOP;
CLOSE cur1;
END$$
DELIMITER ;
SQL Fiddle demo
How to use for loop in MySQL data set ?
FOR x IN (SELECT column FROM table_name WHERE column_2 = input_val)
LOOP
sum_total := sum_total + x.column ;
END LOOP;
This is an example how I used to loop data set in oracle.
How can this be achieved in MySql ?
How about not looping at all. It's SQL after all.
SELECT SUM(`column`) total
FROM table_name
WHERE column_2 = <input_val>
Otherwise use CURSOR
Now, equivalent loop using CURSOR will look like
DELIMITER $$
CREATE PROCEDURE sp_loop(IN input_val INT)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE sum_current, sum_total INT DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT column1 FROM table_name WHERE column2 = input_val;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO sum_current;
IF done THEN
LEAVE read_loop;
END IF;
SET sum_total = sum_total + sum_current;
END LOOP;
CLOSE cur1;
SELECT sum_total;
END$$
DELIMITER ;
Here is SQLFiddle
DROP PROCEDURE IF EXISTS `foo`.`usp_cursor_example`;
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `foo`.`usp_cursor_example`(
IN name_in VARCHAR(255)
)
READS SQL DATA
BEGIN
DECLARE name_val VARCHAR(255);
DECLARE status_update_val VARCHAR(255);
-- Declare variables used just for cursor and loop control
DECLARE no_more_rows BOOLEAN;
DECLARE loop_cntr INT DEFAULT 0;
DECLARE num_rows INT DEFAULT 0;
-- Declare the cursor
DECLARE friends_cur CURSOR FOR
SELECT
name
, status_update
FROM foo.friend_status
WHERE name = name_in;
-- Declare 'handlers' for exceptions
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_rows = TRUE;
OPEN friends_cur;
select FOUND_ROWS() into num_rows;
the_loop: LOOP
FETCH friends_cur
INTO name_val
, status_update_val;
IF no_more_rows THEN
CLOSE friends_cur;
LEAVE the_loop;
END IF;
select name_val, status_update_val;
-- count the number of times looped
SET loop_cntr = loop_cntr + 1;
END LOOP the_loop;
-- 'print' the output so we can see they are the same
select num_rows, loop_cntr;
END
DELIMITER ;
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.