I have a procedure and I need to set the value of a variable the result of one query. That query returns more than one value and Mysql throws the error 1242 subquery returns more than 1 row. I need to save the result in a variable like an array and then use that variable like parameter in other procedure. This is the code I have.
CREATE PROCEDURE getCodes()
BEGIN
#code=(SELECT codref FROM referee WHERE town='Malaga');
CALL getMatch(#code);
END;$$
You need to use CURSOR for iteration:
CREATE PROCEDURE getCodes ()
BEGIN
DECLARE code int;
DECLARE cur1 CURSOR FOR SELECT coderef FROM referee WHERE town='Malaga';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
REPEAT
FETCH cur1 INTO code;
IF NOT done THEN
CALL getMatch(code);
END IF;
UNTIL done END REPEAT;
CLOSE cur1;
END;
See MySQL manual for details.
Related
Scenario: I have a stored procedure that gets data from a table based on 2 inputs: a date and a string (which is a column name). The first procedure is called from another procedure which uses a cursor to loop through rows of a table and pass each row to the string of the first procedure (column names to be checked). My input for the second procedure (which is the one to be called directly) is the date.
Issue: My first procedure is running fine when I call it on its own. My second procedure is throwing some syntax errors that I don't know how to fix.
Obs: I already check some other answers here on this topic
such as Using Cursor in a Loop of a stored procedure and How can I loop through all rows of a table? (MySQL) . Actually my second procedure is now a modified version of a query I found on SE https://dba.stackexchange.com/questions/138549/mysql-loop-through-a-table-running-a-stored-procedure-on-each-entry
Issue: Currently, the code is throwing an error at line 5, in my declare of #colval.
Code:
-- Procedure for looping through rows of `wanted_columns` table:
delimiter $$
drop procedure if exists `data_check_loop` $$
create procedure `data_check_loop`(`wanted_date` date)
begin
set #dateval = `wanted_date`;
declare colval string default null;
-- boolean variable to indicate cursor is out of data
declare done tinyint default false;
-- declare a cursor to select the desired columns from the desired source table
declare cursor1
cursor for
select t1.c1
from `wanted_columns` t1;
-- catch exceptions
declare continue handler for not found set done = true;
-- open the cursor
open cursor1;
my_loop:
loop
fetch next from cursor1 into colval;
if done then
leave my_loop;
else
call `set_column_stats`(colval, dateval);
end if;
end loop;
close cursor1;
end $$
delimiter ;
Question: Any ideas on how to fix this?
You have a couple of problems in your procedure. Firstly, as described in the manual:
DECLARE is permitted only inside a BEGIN ... END compound statement and must be at its start, before any other statements.
So you need to move your
set #dateval = `wanted_date`;
after all the DECLAREs (including the cursor and continue handler).
Secondly, your declaration of colval is incorrect, string is not a valid data type and should be replaced with text:
declare colval text default null;
I am working on a MySQL procedure that creates a summary of one of my tables. The procedure retrieves a dataset and loops through it using a cursor. For each iteration of the loop, the procedure updates another table. The problem I'm having is the loop ends after a single iteration, event though I know that the query I'm running retrieves more than one row.
BEGIN
# Variable declaration section omitted for brevity
DECLARE cur CURSOR FOR SELECT
t.result_id,
t.athlete_id, t.`first`, t.middle, `last`, t.pref, t.birth,t.uss,
t.club_id,t.code,t.club_name,
t.meet_name,t.meet_id,t.`start`,t.`end`,
MIN(t.time) as time,t.age,t.type
FROM sometable t GROUP BY club_id ORDER BY time asc,t.start desc,club_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
read_loop: LOOP
FETCH cur INTO result_id,athlete_id, first_name, middle, last_name, pref, birth,uss,
club_id,club_code,club_name,
meet_name,meet_id,start_date,end_date,
result_time,age,type;
IF done=1 THEN
LEAVE read_loop;
END IF;
SET last_time = result_time;
INSERT INTO toptimes(`result_id`,`club_id`,`agegroup`,`sex`,`distance`,`course`,`stroke`,`data`,`published`)
VALUES(result_id,club_id,AgeGroupID,sex,distance,course,stroke,json,0);
END LOOP read_loop;
CLOSE cur;
END
I'm not clear what the problem is. When I run the select query manually, I get back several rows. Is there a problem running an insert statement inside the loop?
Your code chunk looks good to me.
How do you know that it's running only one iteration (i'm not seeing any
print or select statement for debug purpose)?
Are you getting any error while executing the stored procedure?
I tried to replicate the similar code with "sakila" database (mysql sample db). It's working perfectly. Please check this sql code sample, if it helps you.
DROP PROCEDURE IF EXISTS usp_select_dummy_data ;
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE usp_select_dummy_data()
BEGIN
-- Declare your variables
Declare _var_actor_id int default 0;
DECLARE _var_film_id int default 0;
-- Declare variable used for cursor and loop control
DECLARE done int;
DECLARE loop_counter INT DEFAULT 0;
-- Declare the cursor
DECLARE cur CURSOR FOR
SELECT
actor_id, film_id
FROM film_actor;
-- Declare handlers
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-- Open the cursor
OPEN cur ;
-- Start the loop
read_loop: LOOP
FETCH cur
INTO _var_actor_id, _var_film_id ;
-- break out of the loop if
-- 1. if there is no rows or
-- 2. we've processed them all
IF done = 1 THEN
CLOSE cur ;
LEAVE read_loop ;
END IF;
-- Count the number of times looped
SET loop_counter = loop_counter + 1 ;
END LOOP read_loop ;
-- print the loop count
select loop_counter;
END
I have written a stored proc in mysql when i am running it through hopper it is working fine but when i am trying to run it from mysql workbench or java it is not returning any result and also not showing any exception
I will request you to please help me on this
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `issueitem`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE inventoryids INT DEFAULT 0;
DECLARE batch varchar(39);
DECLARE resultstr varchar(3000) DEFAULT '';
DECLARE exp DATE;
DECLARE mfgdate DATE;
DECLARE availableunit INT;
DECLARE quantity INT DEFAULT 100;
DECLARE oldest_date DATETIME;
DECLARE cur_count INT;
DECLARE que_size INT DEFAULT 0;
DECLARE curs CURSOR FOR SELECT inventoryid,batch,exp,availableunit FROM aashramdata.inventory where itemid=1 ORDER BY exp ASC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN curs;
SET cur_count=quantity;
read_loop: LOOP
FETCH curs INTO inventoryids,batch,exp,availableunit;
IF done THEN
LEAVE read_loop;
END IF;
SET que_size = que_size + availableunit;
IF cur_count >= availableunit THEN
set cur_count=cur_count-availableunit;
set resultstr=CONCAT(resultstr,batch,' - ',exp,' - ',availableunit,' - ');
update aashramdata.inventory set `availableunit`=0 where inventoryid=inventoryids;
END IF;
IF cur_count < availableunit THEN
update aashramdata.inventory set `availableunit`=availableunit-cur_count where inventoryid=inventoryids;
set resultstr=CONCAT(resultstr,batch,' - ',exp,' - ',availableunit-cur_count,' - ');
set cur_count=0;
END IF;
IF que_size >= quantity then
LEAVE read_loop;
END IF;
END LOOP;
CLOSE curs;
select resultstr;
END
Since the procedure is apparently syntactically valid, it's impossible to answer what the problem might be, without some knowledge of the data.
The easiest way to debug a stored procedure is by peppering it with unbounded SELECT statements (that is, selects that are not part of a subquery and not part of an INSERT ... SELECT or SELECT ... INTO) and then running it from the MySQL command line client, which handles multiple result sets from stored procedures much more gracefully than most graphical clients.
For example:
...
SET cur_count=quantity;
SELECT cur_count; -- add this
read_loop: LOOP
FETCH curs INTO inventoryids,batch,exp,availableunit;
SELECT inventoryids,batch,exp,availableunit; -- add this
SELECT done; -- add this
IF done THEN
...
When run from the command line client...
mysql> CALL issueitem();
...output will start rolling out of the console at you, showing you the internal values the procedure is encountering as it iterates the loop.
This, or other SELECT statements like this added elsewhere, will expose the internal variables and this should help you find the problem. You'll need to remove them before you call the procedure from code or even the GUI since the GUI may not handle them well -- it may start opening new tabs or splitting panes or just ignoring everything after the first SELECT.
Note that the last iteration of the loop, you may see the values from the previous iteration repeated since the failed read from the cursor may not reset the variables, but "done" will also transition from 0 to 1 indicating that the cursor has run out of rows and fired the CONTINUE HANDLER, so those values won't actually have been processed twice.
Here it is. It should loop through 120,000 times but it only does twice. SELECT DISTINCT barcode FROM albumitemdetails_custom; returns 120,000 rows when run manually. What is wrong with my code?
DELIMITER $$
CREATE DEFINER=`testuser`#`%` PROCEDURE `AlbumMover`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE barcode varchar(100);
DECLARE cur1 CURSOR FOR SELECT DISTINCT barcode FROM albumitemdetails_custom;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
REPEAT
FETCH cur1 INTO barcode;
CALL AlbumMoverGenre(barcode);
CALL AlbumMoverProducer(barcode);
UNTIL done END REPEAT;
CLOSE cur1;
END
In my experience a loop gets broken if there is a SELECT statement that returns no results, or the FETCH of course. It's impossible to say from your code as you do not show the code for AlbumMoverGenre and AlmbumMoverProducer but I'd check if this is the case in either procedure.
Just looking at your code something is going wrong in either of the subprocedures.
As it breaks at the second iteration I'd get the resultset of your distinct barcodes query and run the subprocedures with that value, and see what the outcome is.
I have got this stored procedure:
DELIMITER //
DROP PROCEDURE IF EXISTS cursor_example//
CREATE PROCEDURE cursor_example()
BEGIN
DECLARE niche_id INT;
DECLARE niche_name VARCHAR(100);
DECLARE curl CURSOR FOR SELECT * FROM `niche`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN curl;
my_loop:LOOP
FETCH curl INTO niche_id, niche_name;
IF done=1 THEN
LEAVE my_loop;
END IF;
END LOOP my_loop;
CLOSE curl;
END//
DELIMITER ;
The question is, how do I take the niche id and niche_name rows out of the cursor after the cursor finished iterating. I cant get a result set from the stored procedure as a variable, cant I? So is the use of cursors for stored procedures is mainly for internal purposes?
If the result is - 'scalar values', then you can use one of this variants:
Run SELECT niche_id, niche_name; from the procedure.
Use OUT paremeters.
If the result is a set of values, then you should populate another table, e.g. temporary table.
Also, if you want to read some data from the table and store it into another table, then try to use INSERT ... SELECT statement instead of opening cursor.