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
Related
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 ;
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 have this as an example function. It's meant to do some more processing on the cursor but for now I'm getting it to total the number of results (I don't want to use count, as I'm planning to extend it later).
delimiter $$
create function testfunction()
returns int reads sql data
begin
declare l_myfield int;
declare iter int;
declare mycur cursor for select myfield from mytable;
set iter = 0;
open mycur;
loop
fetch mycur into l_myfield;
set iter = iter + 1;
end loop;
close mycur;
return iter;
end;
$$
delimiter ;
However I've ended up with the classic:
ERROR 1329 (02000): No data - zero rows fetched, selected, or processed
Note that I do have data returned from the query and I know about using the if-not-found handlers. I've omitted these for brevity.
Where have I gone wrong?
Cheers
You need to add a handler:
delimiter $$
CREATE function testfunction()
returns int reads sql data
BEGIN
DECLARE done INT DEFAULT FALSE;
declare i_myfield int;
declare iter int;
declare mycur cursor for select myfield from mytable;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
set iter = 0;
open mycur;
read_loop: loop
fetch mycur into i_myfield;
IF done THEN
LEAVE read_loop;
END IF;
SET iter = iter + 1;
END loop;
close mycur;
return iter;
END;
$$
delimiter ;
By declaring the handler and using it in the loop, you catch the NOT FOUND error when it reaches the end of the result set. Or if the query returns no results.
I'm unable to get the result of OUT variable in this code, am I doing wrong something? can anyone help?
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE cid INT(10);
DECLARE cuserid VARCHAR(50);
DECLARE cur1 CURSOR FOR SELECT id,username FROM tblcustomer;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO cid,cuserid;
IF done THEN
LEAVE read_loop;
END IF;
SET customers_list = CONCAT(customers_list,cid,':',cuserid,',');
END LOOP;
CLOSE cur1;
END
The procedure prototype is missing from your snippet, but assuming the below:
CREATE PROCEDURE foo(OUT customers_list VARCHAR(100))
BEGIN
...
SET customers_list = 'foo-list';
END ;
This is how you would retreive your "return value":
CALL foo(#var);
SELECT #var; -- outputs "foo-list"
Strictly speaking, a procedure has no "return value". A function has:
CREATE FUNCTION bar() RETURNS VARCHAR(100)
BEGIN
...
RETURN 'bar-list';
END ;
SELECT bar(); -- outputs "bar-list";
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 ;