My procedure with cursor doesnt work - mysql

I have the next procedure:
BEGIN
DECLARE retribAn INTEGER DEFAULT 0;
DECLARE cPost INTEGER(11);
DECLARE done INT DEFAULT 0;
DECLARE curTipo CURSOR FOR
SELECT RETRIBUCION_ANUAL*1.05 AS RET_AN
FROM EMPLEADOS
WHERE ID_CPOSTAL%2=0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN curTipo;
REPEAT
FETCH curTipo INTO retribAn, cPost;
IF NOT done THEN
UPDATE EMPLEADOS
SET RETRIBUCION_ANUAL=retribAn
WHERE ID_CPOSTAL%cPost;
END IF;
UNTIL done END REPEAT;
CLOSE curTipo;
END
when I execute it, sql manager outputs:
Incorrect number of FETCH variables
I do not understand why.
I'm a rookie =D in mysql, and sorry for my English.
Thanks

you are selecting only one column in your cursor query and fetching data into two variables in FETCH
Try this
BEGIN
DECLARE retribAn INTEGER DEFAULT 0;
DECLARE cPost INTEGER(11);
DECLARE done INT DEFAULT 0;
DECLARE curTipo CURSOR FOR
SELECT RETRIBUCION_ANUAL*1.05 AS RET_AN
FROM EMPLEADOS
WHERE ID_CPOSTAL%2=0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN curTipo;
REPEAT
FETCH curTipo INTO retribAn; --remove cPost here
IF NOT done THEN
UPDATE EMPLEADOS
SET RETRIBUCION_ANUAL=retribAn
WHERE ID_CPOSTAL%cPost = 0; --change this to value you want to check
END IF;
UNTIL done END REPEAT;
CLOSE curTipo;
END

Related

What is the differece between my codes when I use cursor to fetch my data with repeat and do while?

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;

Handling multiple nested cursors in stored procedure

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?

Can an inner loop in a mysql procedure use the result of the outer loop

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

mySQL (stored procedure) cursor infinite loop on last row

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

Mysql syntax error on stored procedure

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 //?