I have a stored procedure snippet like this
CREATE DEFINER=`root`#`%` PROCEDURE `new_procedure`()
BEGIN
DECLARE c_id varchar(100) DEFAULT "";
DECLARE cursor1 CURSOR for select id from t1 where name like 's%';
OPEN cursor1;
get_t1: LOOP
FETCH cursor1 into c_id;
p:begin
declare cursor2 cursor for select id from t2 where cl_id=c_id;
open cursor2;
get_t2: loop
fetch project_cursor into p_id;
// perform some tasks
t:begin
declare cursor3 cursor for select id from t3 where pr_id=p_id;
open cursor3;
get_t3:loop
fetch cursor3 into t_id;
IF v_finished = 1 THEN
LEAVE get_t3;
END IF;
//perform some tasks
close cursor3;
select p_id;
end t;
end loop t2;
end p;
END LOOP t1;
END
here select statement is not displaying any data
when i write select under cursor 3 it is working.
did i made any mistake? anything I missed
Some basic logic has been added in your SP, Try it whether this is what you are expecting.
CREATE DEFINER=`root`#`%` PROCEDURE `new_procedure`()
BEGIN
DECLARE c_id VARCHAR(100) DEFAULT "";
DECLARE done1 BOOLEAN DEFAULT FALSE;
DECLARE cursor1 CURSOR FOR SELECT id FROM t1 WHERE name LIKE 's%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done1=TRUE;
OPEN cursor1;
GET_T1: LOOP
FETCH cursor1 INTO c_id;
IF done1 THEN
LEAVE GET_T1;
END IF;
P:BEGIN
DECLARE p_id INT ; -- check which data types suits you, might be int
DECLARE done2 BOOLEAN DEFAULT FALSE;
DECLARE cursor2 CURSOR FOR SELECT id FROM t2 WHERE cl_id=c_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2=TRUE;
OPEN cursor2;
GET_T2: LOOP
FETCH cursor2 INTO p_id;
IF done2 THEN
LEAVE GET_T2;
END IF;
/* perform some task */
T:BEGIN
DECLARE t_id INT ; -- check which data types suits you, might be int
DECLARE done3 BOOLEAN DEFAULT FALSE;
DECLARE cursor3 CURSOR FOR SELECT id FROM t3 WHERE pr_id=p_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done3=TRUE;
OPEN cursor3;
GET_T3:LOOP
FETCH cursor3 INTO t_id;
IF done3 THEN
LEAVE GET_T3;
END IF;
/* perform some tasks */
#select p_id; -- don't know what you are doing with this
END LOOP GET_T3;
CLOSE cursor3;
SET done3=FALSE;
END T;
END LOOP GET_T2;
CLOSE cursor2;
SET done2= FALSE;
END P;
END LOOP GET_T1;
CLOSE cursor1;
SET done1= FALSE;
END
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).
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 ;
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;