I use cursor to fetch my datas.The number of my data is two.But I find that when I use repeat to fetch my data,it always fetch 3 times. And When I use do while,it is right which fetch 2 times.What is the different of thest two ways?How to fixed the first way?
--- The first way:wrong,have two datas but show 3 times
declare v_done tinyint default 0;
declare v_count int default 0;
declare v_id varchar(32);
declare v_result_cur cursor for select distinct(id) from book;
declare continue handler for not found set v_done = 1;
BEGIN
open v_result_cur;
repeat
fetch v_result_cur into v_id;
select v_id;
until v_done end repeat;
close v_result_cur;
END;
The first way is wrong and the second way is right.
--- The second way:right,have two datas but show 2 times
BEGIN
declare v_done tinyint default 0;
declare v_count int default 0;
declare v_id varchar(32);
declare v_result_cur cursor for select distinct(id) from book;
BEGIN
open v_result_cur;
dept_loop:WHILE(v_done=0) DO
fetch v_result_cur into v_id;
select v_id;
IF v_done=1 THEN
LEAVE dept_loop;
END IF;
END WHILE dept_loop;
close v_result_cur;
END;
Just add a justment before the execute statement.
open v_result_cur;
repeat
fetch v_result_cur into v_id;
IF NOT v_done THEN
select v_id;
END IF;
until v_done end repeat;
close v_result_cur;
How can I use two cursors in the same routine? I am getting "Variable or condition declaration after cursor or handler declaration" error while creating procedure.
I have to use both integer outerDone & innerDone to check whether cursor points to null or not.
I haven't worked on stored-procedure yet. Could anybody sort this problem please. Thanks in advance!!
DELIMITER ##;
create procedure updateStopTimeColumn()
BEGIN
DECLARE outerDone INT DEFAULT 0;
DECLARE vehicle_record CURSOR FOR SELECT `vehicleId` FROM `vehicle`;
DECLARE current_record CURSOR FOR SELECT `id`,`tsTime`,`teTime` FROM `trip` where `vehicleId`=vehId order by `tsTime`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET outerDone = 1;
DECLARE vehId,tripId CHAR(250);
DECLARE currentTsTime,currentTeTime time;
OPEN vehicle_record;
REPEAT
FETCH vehicle_record INTO vehId;
block2 : BEGIN
DECLARE innerDone INT DEFAULT 0;
DECLARE tempTripId CHAR(250);
DECLARE tempTsTime,tempTeTime time;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET innerDone = 1;
OPEN current_record;
FETCH current_record INTO tempTripId, tempTsTime,tempTeTime;
REPEAT
FETCH current_record INTO tripId,currentTsTime,currentTeTime;
UPDATE trip set stopTime=(currentTeTime-tempTsTime) where id=tempTripId and tempTeTime IS NOT NULL;
SET tempTripId=tempId;
SET tempTsTime=currentTsTime;
SET tempTeTime=currentTeTime;
UNTIL innerDone END REPEAT;
END block2;
CLOSE current_record;
UNTIL outerDone END REPEAT;
CLOSE vehicle_record;
END; ##
DELIMITER;
Have you tried moving the
DECLARE vehId,tripId CHAR(250);
DECLARE currentTsTime,currentTeTime time;
statements to before your cursors?
I have tried to create the following procedure in mysql
PROCEDURE fix()
BEGIN
DECLARE event_id_ INT;
DECLARE gate_number INT;
DECLARE l_done INT DEFAULT 0;
DECLARE curs_event_id CURSOR FOR SELECT DISTINCT event_id FROM history_15min;
DECLARE curs_gate_number CURSOR FOR SELECT DISTINCT gate_number
FROM history_15min WHERE event_id =event_id_;
( -- HERE IS THE PROBLEM - event_id_ IS BLANK THERE FOR THE INNER LOOP RETURNS NO RESULTS ....)
DECLARE CONTINUE HANDLER FOR NOT FOUND SET l_done=1;
OPEN curs_event_id;
event_loop : LOOP
FETCH curs_event_id INTO event_id_;
IF l_done=1 THEN LEAVE event_loop;
END IF;
OPEN curs_gate_number;
gate_loop : LOOP
FETCH curs_gate_number INTO gate_number;
IF l_done=1 THEN LEAVE gate_loop;
END IF;
insert into t value ('1');
END LOOP gate_loop;
CLOSE curs_gate_number;
SET l_done=0;
END LOOP event_loop;
CLOSE curs_event_id;
END
Is there a way i can get the result from the first loop to be a variable in the second loop ??
Thank CHill60 , your link had the answer i was looking for
here is the correct way to perform the nested loop :
PROCEDURE fix()
BLOCK1: BEGIN
DECLARE colA_ INT;
DECLARE l_done INT DEFAULT 0;
DECLARE curs_colA CURSOR FOR SELECT DISTINCT colA FROM tableA;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET l_done=1;
OPEN curs_colA;
first_loop : LOOP
FETCH curs_colA INTO colA_;
IF l_done=1 THEN LEAVE first_loop;
END IF;
BLOCK2: BEGIN
DECLARE calB_ INT;
DECLARE l_done INT DEFAULT 0;
DECLARE curs_calB CURSOR FOR SELECT DISTINCT calB FROM tableB WHERE colA = colA_;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET l_done=1;
OPEN curs_calB;
second_loop : LOOP
FETCH curs_calB INTO calB_;
IF l_done=1 THEN LEAVE second_loop;
END IF;
insert into tmp value ('1');
END LOOP second_loop;
CLOSE curs_calB;
SET l_done=0;
END BLOCK2;
END LOOP first_loop;
CLOSE curs_colA;
END BLOCK1
I have following code: Problem is on the last row of creature_y loop doesn't end and inserts same values (with increased guid) infinitely.
I tried few ways with changing continue handler but seems it is not that.
DELIMITER $$
DROP PROCEDURE IF EXISTS creature_copy
$$
CREATE PROCEDURE creature_copy ()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE new_guid INT(10);
-- Creature definition
DECLARE y_guid INT(10);
DECLARE y_id mediumint(8);
DECLARE y_map int(5);
DECLARE y_modelid mediumint(8);
DECLARE y_position_x float(10);
DECLARE y_position_y float(10);
DECLARE y_position_z float(10);
DECLARE y_orientation float(10);
DECLARE y_spawntimesecs INT(10);
DECLARE y_curhealth INT(10);
DECLARE y_curmana INT(10);
DECLARE y_MovementType tinyint(3);
-- waypoints definition
DECLARE w_id INT(10);
DECLARE w_point mediumint(8);
DECLARE w_position_x float(10);
DECLARE w_position_y float(10);
DECLARE w_position_z float(10);
DECLARE w_orientation float(10);
-- Generate creatures map
DECLARE creature_sel CURSOR FOR
SELECT guid,id, map, modelid, position_x, position_y, position_z, orientation, spawntimesecs, curhealth, curmana, MovementType
FROM creature_y;
-- Generate waypoints map
DECLARE waypoint_sel CURSOR FOR
SELECT id, point, position_x, position_y, position_z, orientation
FROM creature_movement
WHERE creature_movement.id = y_guid;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN creature_sel;
-- Cleanup tables before re-running
TRUNCATE creature_t;
TRUNCATE waypoint_data;
-- Set starting guid before loop
SET new_guid = 504115;
creature_loop:LOOP
if done = 1 THEN
-- set done = 0;
CLOSE creature_sel;
LEAVE creature_loop;
end if;
SET new_guid = new_guid + 1;
FETCH creature_sel INTO y_guid, y_id, y_map, y_modelid, y_position_x, y_position_y, y_position_z, y_orientation, y_spawntimesecs, y_curhealth, y_curmana, y_MovementType;
INSERT INTO creature_t(guid, id, map, modelid, position_x, position_y, position_z, orientation, spawntimesecs, curhealth, curmana, MovementType) VALUES(new_guid, y_id, y_map, y_modelid, y_position_x, y_position_y, y_position_z, y_orientation, y_spawntimesecs, y_curhealth, y_curmana, y_MovementType);
OPEN waypoint_sel;
waypoint_loop:LOOP
FETCH waypoint_sel INTO w_id, w_point, w_position_x, w_position_y, w_position_z, w_orientation;
IF done = 1 THEN
SET done = 0;
LEAVE waypoint_loop ;
END IF;
INSERT INTO waypoint_data(id, point, position_x, position_y, position_z, orientation) VALUES (new_guid, w_point, w_position_x, w_position_y, w_position_z, w_orientation);
END LOOP waypoint_loop;
CLOSE waypoint_sel;
END LOOP creature_loop;
CLOSE creature_sel;
END;
I have found solution to this.
To use 2 different continue handlers (to see whether cursor is at end) you need to split code into blocks
BLOCK1: BEGIN
DECLARE done INT DEFAULT 0;
-- First cursor
DECLARE sel CURSOR FOR
SELECT column
FROM table;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN sel;
sel_loop:LOOP
if done = 1 THEN
set done = 0;
CLOSE sel;
LEAVE sel_loop;
end if;
FETCH sel INTO variable1;
-- Do something in loop
-- Start second code-block
BLOCK2: BEGIN
DECLARE done2 INT DEFAULT 0;
-- define second cursor
DECLARE sel2 CURSOR FOR
SELECT column
FROM table
WHERE column = condition;
-- define second handler
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2 = 1;
-- now you can make second cursor loop and it will finish properly.
OPEN sel2;
sel2_loop:LOOP
FETCH sel2 INTO variable2;
IF done2 = 1 THEN
SET done2 = 0;
LEAVE sel2_loop ;
END IF;
-- do something in second loop
END LOOP waypoint_loop;
CLOSE waypoint_sel;
-- End your code blocks and close first loop / cursor
END BLOCK2;
END LOOP sel_loop;
CLOSE sel;
END BLOCK1
I run this code as a sql script from command line, and I get "you have an error in your SQL syntax" almost in all lines! Any ideas what is wrong here?
CREATE PROCEDURE updatemandate()
BEGIN
DECLARE _mandate_id BIGINT(20);
DECLARE _has_succesful_payment tinyint(1);
DECLARE done INT DEFAULT 0;
DECLARE cnt INT;
DECLARE mandateCursor CURSOR FOR Select mandate_id, has_succesful_payment From mandates;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN mandateCursor;
allmandates: LOOP
Fetch mandateCursor INTO _mandate_id, _has_succesful_payment;
IF done THEN LEAVE allmandates;
END IF;
Select COUNT(*) FROM payments WHERE mandate_id=_mandate_id AND status='OK' into cnt;
IF cnt>0 THEN
SET _has_succesful_payment=1;
END IF;
END LOOP allmandates;
CLOSE mandateCursor;
END
The ; character is the default delimiter, so when MySQL sees the first ; it thinks you are done. When you create a sproc, you need to declare a different delimiter character, like so:
DELIMITER $$
CREATE PROCEDURE updatemandate()
READS SQL DATA
BEGIN
DECLARE _mandate_id BIGINT(20);
DECLARE _has_succesful_payment tinyint(1);
DECLARE done INT DEFAULT 0;
DECLARE cnt INT;
DECLARE mandateCursor CURSOR FOR Select mandate_id, has_succesful_payment From mandates;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN mandateCursor;
allmandates: LOOP
Fetch mandateCursor INTO _mandate_id, _has_succesful_payment;
IF done THEN LEAVE allmandates;
END IF;
Select COUNT(*) FROM payment WHERE mandate_id=_mandate_id AND status='OK' into cnt;
IF cnt>0 THEN
SET _has_succesful_payment=1;
END IF;
END LOOP allmandates;
CLOSE mandateCursor;
END$$
DELIMITER ;
Also a good idea to add the READS SQL DATA to the sproc definition in case you need to support binary logging.
Have you tried putting delimiter // before the CREATE statement and change the last line with END //?