I have following cursor with parameter. Now I need to set parameter during loop. Is their a short way to do this?
Cursor:
DECLARE curs1 CURSOR FOR
SELECT USER_ID,affiliate_id
FROM `wpmr_aff_referrals` WHERE affiliate_id=AFFILIATEID;
Cursor body part:
OPEN curs1;
read_loop : LOOP
FETCH curs1 INTO USERID,AFFILIATEID;
IF (vCNT>=3) THEN
set AFFILIATEID=10;
ELSE
set new.affiliate_id= 5;
END IF;
END LOOP read_loop;
CLOSE curs1;
At set AFFILIATEID=10; it should be re-opened like in Oracle we do open cursor as c_emp (23);
Try this with inner block and loop.
OPEN curs1;
read_loop : LOOP
FETCH curs1 INTO USERID,AFFILIATEID;
IF (vCNT>=3) THEN
set AFFILIATEID=10;
ELSE
set new.affiliate_id= 5;
END IF;
BLOCK2: begin
DECLARE USERID1 varchar(50);
DECLARE AFFILIATEID1 varchar(50) default
declare curs2 cursor for
SELECT USER_ID,affiliate_id
FROM `wpmr_aff_referrals` WHERE affiliate_id=AFFILIATEID;
open curs2;
LOOP2: loop
FETCH curs2 INTO USERID1,AFFILIATEID1;
end loop LOOP2;
CLOSE curs2;
end BLOCK2;
END LOOP read_loop;
CLOSE curs1;
i am trying to nest two cursors.however i am getting syntax for line "declare no_more rows boolean:=FALSE".i am using phpMyAdmin and running in this on MySQL console. Also can i do this without declaring stored procedure? please help me out here. this thing is breaking my head past three days. following is the best code i could write:
Delimiter $$
create procedure test1()
BEGIN
BLOCK1: begin
declare v_col1 int(10);
declare no_more_rows boolean1 := FALSE;
declare cursor1 cursor for
select content_id
from topic_list where topic_id=1;
declare continue handler for not found
set no_more_rows1 := TRUE;
open cursor1;
LOOP1: loop
fetch cursor1
into v_col1;
if no_more_rows1 then
close cursor1;
leave LOOP1;
end if;
BLOCK2: begin
declare v_col2 int(10);
declare no_more_rows2 boolean := FALSE;
declare cursor2 cursor for
select content_id
from content_upvotes
where u_id_upvoter = v_col1;
declare continue handler for not found
set no_more_rows2 := TRUE;
open cursor2;
LOOP2: loop
fetch cursor2
into v_col2;
if no_more_rows then
close cursor2;
leave LOOP2;
end if;
end loop LOOP2;
end BLOCK2;
end loop LOOP1;
end BLOCK1;
end $$
DELIMITER ;
If you check mysql's documentation on declare syntax, xou can see that the defsult value is set using the DEFAULT keyword, not the asdignment operator:
DECLARE var_name [, var_name] ... type [DEFAULT value]
So, your declaration should be
declare no_more_rows tinyint(1) default 0;
I also mapped the boolean type to tinyint(1).
According to this answer Call a stored procedure for each row returned by a query in MySQL described as following:
CREATE PROCEDURE foo() BEGIN
DECLARE done BOOLEAN DEFAULT FALSE;
DECLARE _id BIGINT UNSIGNED;
DECLARE cur CURSOR FOR SELECT id FROM objects WHERE ...;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done := TRUE;
OPEN cur;
testLoop: LOOP
FETCH cur INTO _id;
IF done THEN
LEAVE testLoop;
END IF;
CALL testProc(_id);
END LOOP testLoop;
CLOSE cur;
END
How can i set a variable and increment it over each iteration?
The following code does't work and I don't know why.
CREATE PROCEDURE foo() BEGIN
DECLARE done BOOLEAN DEFAULT FALSE;
DECLARE _id BIGINT UNSIGNED;
DECLARE counter INT DEFAULT 0;
DECLARE cur CURSOR FOR SELECT id FROM objects WHERE ...;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done := TRUE;
OPEN cur;
testLoop: LOOP
FETCH cur INTO _id;
IF done THEN
LEAVE testLoop;
END IF;
CALL testProc(_id);
counter = counter + 1;
END LOOP testLoop;
CLOSE cur;
END
Hi I have a nested cursor with three levels on it...
DECLARE campaign_csr CURSOR FOR SELECT cid FROM tempCampaign;
DECLARE date_csr CURSOR FOR SELECT header,ranges FROM tempDate ORDER BY id;
DECLARE level_csr CURSOR FOR SELECT 1st,2nd,3rd FROM tempDispoLevels ORDER BY 1st,2nd;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done := TRUE;
OPEN campaign_csr;
campaign_loop:LOOP
FETCH campaign_csr INTO xcid;
IF v_done THEN
CLOSE campaign_csr;
LEAVE campaign_loop;
END IF;
select "1";
OPEN date_csr;
date_loop: LOOP
FETCH date_csr INTO xheader,xranges;
IF v_done THEN
SET v_done := FALSE;
CLOSE date_csr;
LEAVE date_loop;
END IF;
select "2";
OPEN level_csr;
level_loop: LOOP
FETCH level_csr INTO x1level,x2level,x3level;
IF v_done THEN
SET v_done := FALSE;
CLOSE level_csr;
LEAVE level_loop;
END IF;
select "3";
END LOOP level_loop;
END LOOP date_loop;
END LOOP campaign_loop;
the problem is the outer loop (which in this case campaign_loop) doesn't read all records. Is there any way around this.
Thank you.
You know each outer loop has not finished when you process an inner loop (otherwise you wouldn't be processing the inner loop), so simply reset v_done after each inner loop:
SET v_done := FALSE;
That's all you need to do.
Don't create a boolean variable for each cursor and copy the value; logically they can only ever be true!
I discover a work around on this: The added variables are for looping the outside cursor until to the last row.
Declare 3 more v_done variable
DECLARE v_done BOOLEAN DEFAULT FALSE; //this is the original
DECLARE v_done1 BOOLEAN DEFAULT FALSE; //added
DECLARE v_done2 BOOLEAN DEFAULT FALSE; //added
DECLARE v_done3 BOOLEAN DEFAULT FALSE;//added
Keep this line:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done := TRUE;
Change every declaration of cursor:
OPEN campaign_csr;
campaign_loop:LOOP
FETCH campaign_csr INTO xcid;
IF v_done THEN
CLOSE campaign_csr;
LEAVE campaign_loop;
END IF;
into:
OPEN campaign_csr;
campaign_loop:LOOP
FETCH campaign_csr INTO xcid;
SET v_done1 := v_done;
IF v_done1 THEN
SET v_done := FALSE;
CLOSE campaign_csr;
LEAVE campaign_loop;
END IF;
This code works for me.
DELIMITER $$
USE `yourDatabase`$$
DROP PROCEDURE IF EXISTS `yourProcedure`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `yourProcedure`()
BEGIN
DECLARE xcid INT;
DECLARE xcid2 INT;
DECLARE xcid3 INT;
DECLARE v_done BOOLEAN DEFAULT FALSE;
DECLARE v_done1 BOOLEAN DEFAULT FALSE;
DECLARE v_done2 BOOLEAN DEFAULT FALSE;
DECLARE v_done3 BOOLEAN DEFAULT FALSE;
DECLARE campaign_csr CURSOR FOR SELECT column FROM yourTable;
DECLARE date_csr CURSOR FOR SELECT column FROM yourTable2;
DECLARE level_csr CURSOR FOR SELECT column FROM yourTable3;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done := TRUE;
OPEN campaign_csr;
campaign_loop:LOOP
FETCH campaign_csr INTO xcid;
SET v_done1 := v_done;
IF v_done1 THEN
SET v_done := FALSE;
CLOSE campaign_csr;
LEAVE campaign_loop;
END IF;
select "1";
OPEN date_csr;
date_loop: LOOP
FETCH date_csr INTO xcid2;
SET v_done2 := v_done;
IF v_done2 THEN
SET v_done := FALSE;
CLOSE date_csr;
LEAVE date_loop;
END IF;
select "2";
OPEN level_csr;
level_loop: LOOP
FETCH level_csr INTO xcid2;
SET v_done3 := v_done;
IF v_done3 THEN
SET v_done := FALSE;
CLOSE level_csr;
LEAVE level_loop;
END IF;
select "3";
END LOOP level_loop;
END LOOP date_loop;
END LOOP campaign_loop;
END$$
DELIMITER ;
I wish to do something which appear a bit complicated in MySQL.
In fact, I wish to open a cursor, do a loop, and in this loop, open a second cursor using the data from the previous fetch to be executed, and re-loop on the results.
DECLARE idind INT;
DECLARE idcrit INT;
DECLARE idindid INT;
DECLARE done INT DEFAULT 0;
DECLARE done2 INT DEFAULT 0;
DECLARE curIndicateur CURSOR FOR SELECT id_indicateur FROM indicateur;
DECLARE curCritereIndicateur CURSOR FOR SELECT C.id_critere FROM critere C where C.id_indicateur=idind;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
set idindid=54;
OPEN curIndicateur;
REPEAT
FETCH curIndicateur INTO idind;
open curCritereIndicateur;
REPEAT
FETCH curIndicateur INTO idcrit;
INSERT INTO SLA_DEMANDE_STATUS (iddemande,idindicateur,indicateur_status,progression) values('0009',idcrit,'OK',10.0);
UNTIL done END REPEAT;
close curCritereIndicateur;
UNTIL done END REPEAT;
CLOSE curIndicateur;
In fact, how to do 'Until done' differently for the two cursors, because you can only declare one handler for SQLSTATE?
If the first ends, the second ends too.
You need to define a new BLOCK inside your 1st cursor loop and use different Declares in that block.
Something like:
BLOCK1: begin
declare v_col1 int;
declare no_more_rows boolean1 := FALSE;
declare cursor1 cursor for
select col1
from MyTable;
declare continue handler for not found
set no_more_rows1 := TRUE;
open cursor1;
LOOP1: loop
fetch cursor1
into v_col1;
if no_more_rows1 then
close cursor1;
leave LOOP1;
end if;
BLOCK2: begin
declare v_col2 int;
declare no_more_rows2 boolean := FALSE;
declare cursor2 cursor for
select col2
from MyOtherTable
where ref_id = v_col1;
declare continue handler for not found
set no_more_rows2 := TRUE;
open cursor2;
LOOP2: loop
fetch cursor2
into v_col2;
if no_more_rows then
close cursor2;
leave LOOP2;
end if;
end loop LOOP2;
end BLOCK2;
end loop LOOP1;
end BLOCK1;
Correct me if I'm wrong, but it looks like what you are trying to do is a bulk insert of records into your "SLA_DEMANDE_STATUS" table. Include every criteria for every indicator found and default it with the values of '0009', 'OK' and 10.0 per each indicator's Criteria ID.
This can all be done in a single SQL-Insert. INSERT INTO ... from a SQL-Select...
Now, if you want to only include a single "id_indicateur" entry, you can add that to the WHERE clause of the select statement.
Notice that my SQL-Select has forced values to correspond with the columns you want to have populated. They will all be inserted to the destination table by the same name. The nice thing about this, you can just run the SQL-SELECT portion just to see the data you would EXPECT to have inserted... if its incorrect, you can adjust it to fit whatever restrictions you want.
insert into SLA_DEMANDE_STATUS
( iddemande,
idindicateur,
indicateur_status,
progression )
SELECT
'0009' iddemande,
c.id_criterere idindicateur,
'OK' indicateur_status,
10.0 progression
FROM
indicateur i;
JOIN critere c
ON i.id_indicateur = c.id_indicateur
you could use loop,and reset the value of the handle,like this:
get_something:loop
open cur;
fetch cur into temp_key;
if no_more_record=1 then
set no_more_record=0;
close cur;
leave get_something;
else
//do your job;
end if;
end loop;
Or redefine the CONTINUE HANDLE:
//...
LOOP1: LOOP
fetch cursor1
into v_col1;
if no_more_rows1 then
close cursor1;
leave LOOP1;
end if;
//...
SET no_more_rows1=false;//That's new
END LOOP LOOP1;
It seems that all select statements inside a loop execute the CONTINUE HANDLE
DECLARE _idp INT;
DECLARE _cant INT;
DECLARE _rec INT;
DECLARE done INT DEFAULT 0;
-- DefiniciĆ³n de la consulta
DECLARE primera CURSOR FOR SELECT dp.id_prod, SUM(dp.cantidad) AS cantidad, pp.receta FROM tm_detalle_pedido AS dp INNER JOIN tm_producto_pres AS pp
DECLARE segunda CURSOR FOR SELECT id_ins, cant FROM tm_producto_ingr WHERE id_pres = _idp;
-- DeclaraciĆ³n de un manejador de error tipo NOT FOUND
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-- Abrimos el primer cursor
OPEN primera;
REPEAT
FETCH primera INTO _idp, _cant, _rec;
IF NOT done THEN
OPEN segunda;
block2: BEGIN
DECLARE doneLangLat INT DEFAULT 0;
DECLARE _ii INT;
DECLARE i FLOAT;
DECLARE _canti FLOAT;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET doneLangLat = 1;
REPEAT
FETCH segunda INTO _ii,_canti;
IF NOT doneLangLat THEN
IF _rec = 1 THEN
SET i = _canti * _cant;
-- Insertamos
INSERT INTO tm_inventario (id_ins,id_tipo_ope,id_cv,cant,fecha_r)
VALUES (_ii, 2, #id, i, _fecha);
END IF;
END IF;
UNTIL doneLangLat END REPEAT;
END block2;
CLOSE segunda;
END IF;
UNTIL done END REPEAT;
CLOSE primera;