I have a mysql procedure that counts number of activated users in members table. I want the procedure to, when done counting, display result stored in variable num in table. But I can select num only inside the loop, so every iteration new table is displayed, and when I put select after loop, nothing is being displayed.
delimiter $$
create procedure users()
begin
declare un varchar(25);
declare num int default 0;
declare idd,act int;
declare c cursor for
select id,username,activated from members;
open c;
l: loop
fetch c into idd,un,act;
if act = 1 then set num = num+1;
end if;
end loop l;
close c;
select num; <---------------
end$$
delimiter ;
Related
I think I'm narrowing in on my issue. I have a loop that is only firing once:
DELIMITER $$
DROP PROCEDURE IF EXISTS `thread_updates` $$
CREATE PROCEDURE `thread_updates`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE my_curr_id INT DEFAULT NULL;
-- DECLARE other vars
DECLARE fixer_cursor CURSOR FOR
SELECT DISTINCT(id)
FROM log
WHERE date >= '2018-01-01';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN fixer_cursor;
REPEAT
FETCH fixer_cursor INTO my_curr_id;
IF NOT done THEN
SELECT data FROM table WHERE id = my_curr_id; -- This may not exist
-- Do other stuff with 'data' or NULL from above
END IF;
UNTIL done END REPEAT;
CLOSE fixer_cursor;
END $$
DELIMITER ;
I think the issue may be that inside the IF NOT done THEN loop, I have a few select statements that may be trying to select results that don't exist (not found).
This is fine (for me) as the logic continues along using NULL values in those spots, but I suspect that my CONTINUE HANDLER FOR NOT FOUND is catching the NOT FOUND warning that these selects throw inside the loop and are thus stopping the entire loop prematurely.
How can I listen for NOT FOUND warning on my cursor only?
Or, how can I suppress the NOT FOUND warning in my MAYBE FOUND select statements inside my loop so my loop continues?
I think I have solved the issue by implementing a counter in a loop rather than relying on the NOT FOUND handler:
DELIMITER $$
DROP PROCEDURE IF EXISTS `thread_updates` $$
CREATE PROCEDURE `thread_updates`()
BEGIN
DECLARE my_total INT DEFAULT NULL; -- Declare total
DECLARE my_counter INT DEFAULT 0; -- Declare counter starting at 0
DECLARE my_curr_id INT DEFAULT NULL;
-- DECLARE other vars
DECLARE fixer_cursor CURSOR FOR
SELECT DISTINCT(id)
FROM log
WHERE date >= '2018-01-01';
OPEN fixer_cursor;
SELECT FOUND_ROWS() INTO my_total; -- Get total number of rows
my_fixerloop: LOOP
FETCH fixer_cursor INTO my_curr_id;
IF my_counter >= my_total THEN -- Compare counter to total
CLOSE fixer_cursor;
LEAVE my_fixerloop;
END IF;
SET my_counter = my_counter + 1; -- Increment by one for each record
SELECT data FROM table WHERE id = my_curr_id; -- This may not exist
-- Do other stuff with 'data' or NULL from above
END LOOP;
END $$
DELIMITER ;
I need to generate a table with one field. The field will contain numbers from 0 to some n with increments of m. So, (0, m, 2m, 3m, ... n-m, n)
Thanks!
You can use recursive CTE to generate the numbers like below, 5 is increment and 100 is max value. may require minor changes for MySQL syntax, as I have written this query for SQL server.
WITh MyNumbers as(
Select 0 as Num
UNION all
SELECT Num + 5 as Num from MyNumbers where num <= 100
)
select * from MyNumbers
DELIMITER //
drop procedure if exists counter//
-- This pocedure count from 0 -> n and insert the values to the new_table
create procedure counter(IN number1 int)
begin
declare idx INT default 0;
while idx <= number1 do
insert into new_table values(idx);
set idx = idx + 1;
end while;
end//
drop procedure if exists mission//
-- This procedure reading a table with single field which contains numbers, and calling for each number to the procedure 'counter'
create procedure mission()
begin
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_num INT DEFAULT 0;
-- declare cursor for all the numbers in 'TWN' table
DEClARE num_cursor CURSOR FOR
SELECT TWN.number FROM TWN;
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;
-- Start the iterator
open num_cursor;
get_num: LOOP
FETCH num_cursor INTO v_num;
IF v_finished = 1 THEN
-- If the procedure have been called for all the numbers
LEAVE get_num;
END IF;
-- Call the procedure for the current number
call counter(v_num);
END LOOP get_num;
-- Close the iterator
CLOSE num_cursor;
end//
DELIMITER ;
-- Clear the table 'new_table' from values
truncate table new_table;
-- call the procedure 'mission'
call mission();
-- Display the results
select * from new_table;
I am using a procedure to loop through a table and perform a different procedure on each row (this procedure uses other tables and works fine, returns correct result set). Here is my attempt:
DELIMITER $$
CREATE PROCEDURE user_loop()
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
SELECT COUNT(*) FROM users INTO n;
SET i=0;
WHILE i<n DO
SET #cur_id = (SELECT user_id from users LIMIT i,1);
INSERT INTO results CALL other_proc(#cur_id);
SET i = i + 1;
END WHILE;
End;
$$
Not sure what the correct syntax is in order to do this, I looked but couldn't find any examples.
I have a little problem. Looks like the procedure does not exist. Somehow it's dropped after the creation. I get different error each time i change something. I'm not really sure what's causing the error, maybe I'm not allowed to drop procedures and creating them in the same query.
I hope you guys can help me out.
drop procedure if exists refIntChk;
DELIMITER //
CREATE PROCEDURE refIntChk(IN district INT(11), OUT b INT(1))
BEGIN
DECLARE b INT(1);
IF district IN (select dist FROM t13)
THEN
SET b = 1;
ELSE
SET b = 0;
END IF;
END; //
DELIMITER ;
drop procedure gen if exists ;
DELIMITER //
CREATE PROCEDURE gen()
BEGIN
DECLARE rows INT(11) DEFAULT (SELECT COUNT(dist) FROM t13);
DECLARE district INT(11);
DECLARE custname VARCHAR(16);
DECLARE revenue FLOAT;
DECLARE x INT DEFAULT 10000;
DECLARE outvar INT(11);
WHILE x > 0
DO
SET district = FLOOR(RAND()*rows)+1;
CALL refIntChk(district, outvar);
IF outvar = 1
THEN
SET custname = substring(MD5(RAND()), -16);
SET revenue = (RAND() * 10);
INSERT INTO t14 VALUES(NULL, custname, district, revenue);
SET x = x - 1;
END IF;
END WHILE;
END;//
DELIMITER ;
CALL gen();
When you get errors, it's usually good to run each statement, one by one, and see which one is producing the error.
The second DROP procedure statement should be:
drop procedure if exists gen;
I am running a stored procedure. The issue seems to be that it will go into the if statement. Also for some reason or another regardless of how many selects I use it will only return the first. I've copied this from another stored procedure that works like a charm, but this one just won't go. Any ideas?
DROP PROCEDURE IF EXISTS genSelPriceTier;
DELIMITER $$
CREATE PROCEDURE genSelPriceTier(tier_id INT, default_id INT)
BEGIN
DECLARE rowCount INT DEFAULT 0;
SELECT * FROM price_tier WHERE price_tier_id = tier_id;
SET rowCount = FOUND_ROWS();
IF rowCount < 1 THEN
SELECT * FROM price_tier WHERE price_tier_id = default_id;
END IF;
END$$
DELIMITER ;
There is a bug reported related to the usage of FOUND_ROWS(). So, I recommend using Count(*) for the number of rows returned. Something like the following should work.
DROP PROCEDURE IF EXISTS genSelPriceTier;
DELIMITER $$
CREATE PROCEDURE genSelPriceTier(tier_id INT, default_id INT)
BEGIN
DECLARE rowCount INT DEFAULT 0;
SELECT COUNT(*) INTO rowCount FROM price_tier WHERE price_tier_id = tier_id
IF rowCount < 1 THEN
SELECT * FROM price_tier WHERE price_tier_id = default_id;
END IF;
END$$
DELIMITER ;