How can you in a procedure function in mysql check if the cursor returns anything?
Is it possible to avoid doing the IF (SELECT COUNT(*) FROM stock ... and instead check up on the _cur variable somehow?
procedure function
DELIMITER $$
DROP FUNCTION IF EXISTS `stock_first_available_id` $$
CREATE DEFINER=`dynaccount`#`localhost` FUNCTION `stock_first_available_id`(_running_total_limit INT, _product_id INT, _group_id INT) RETURNS INT
BEGIN
DECLARE _running_count INT default 0;
DECLARE _id INT;
DECLARE _current_id INT;
DECLARE _sum_count INT;
DECLARE _cur CURSOR FOR SELECT id, count FROM stock WHERE group_id=_group_id && type=2 && product_id=_product_id ORDER BY time DESC, id DESC;
IF (SELECT COUNT(*) FROM stock WHERE group_id=_group_id && type=2 && product_id=_product_id) = 0 THEN
RETURN 0;
END IF;
OPEN _cur;
read_loop: LOOP
FETCH _cur INTO _id, _sum_count;
SET _running_count = _running_count + _sum_count;
SET _current_id = _id;
IF _running_count > _running_total_limit THEN
LEAVE read_loop;
END IF;
END LOOP read_loop;
CLOSE _cur;
RETURN _current_id;
END $$
DELIMITER ;
Add a continue handler to your cursor. See exanples from MySQL documentation.
http://dev.mysql.com/doc/refman/5.0/en/cursors.html
Related
The task is create a stored procedure which creates a statistic of students by city. The result should be like - -
`
delimiter $$
create procedure courcity()
begin
declare list_stud text default '';
declare _cty varchar(50);
declare _count int;
declare _name_stud varchar(50);
declare done integer default FALSE;
declare cty_cur cursor for select cty, count(*) as count from student group by cty order by cty;
declare stud_cur cursor for select name_stud from student where cty = _cty;
declare continue handler for NOT found set done = TRUE;
create temporary table return_table(
cty varchar(50),
count_stud int,
list_stud text default ''
);
begin
declare list_stud text default '';
declare _cty varchar(50);
declare _count int;
declare _name_stud varchar(50);
declare done integer default FALSE;
declare cty_cur cursor for select cty, count(*) as count from student group by cty order by cty;
declare stud_cur cursor for select name_stud from student where cty = _cty;
open cty_cur;
open stud_cur;
read_loop: LOOP
fetch cty_cur into _cty, _count;
IF done THEN
LEAVE read_loop;
read_loop1: loop
fetch stud_cur into _name_stud;
if done then leave read_loop1;
list_stud := list_stud || _name_stud || ', ';//here is the problem
end loop;
close stud_cur;
insert into return_table values (_cty, _count, list_stud);
list_stud := '';
end loop;
close cty_cur;
select * from return_table;
end;$$
delimiter ;
`
Can't create this procedure due to this problem.Can't find mistake.
IF THEN must be closed with END IF;
https://www.mysqltutorial.org/mysql-if-statement/
IF condition THEN
statements;
END IF;
|| is definitely not correct in MySQL. on the right side of := you should have a variable or a valid expression.
I have been debugging a SQL stored procedure which has to take values (in my code ID and Numb) form table A based on the values (ID) present in the Table C, then square the Numb and store it in Table B i.e. all the things ID, Numb and Square.
I am not able to figure out the problem in the below code
DELIMITER $$
CREATE PROCEDURE matlab.squaring
BEGIN
DECLARE finish BOOLEAN DEFAULT 0; # <- set up initial conditions
DECLARE square BIGINT(10);
DECLARE ID INT(10);
DECLARE Numb INT (10);
DECLARE id_cur CURSOR FOR
SELECT ID, Numb FROM A WHERE EXISTS ( SELECT ID FROM c);
SET #square= #Numb * #Numb
INSERT INTO B
(
ID ,
Numb ,
square
) values ( ID , Numb, square);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finish = TRUE;
OPEN id_cur;
the_loop : LOOP
FETCH id_cur INTO ID;
IF finish THEN
CLOSE id_cur;
LEAVE the_loop;
END IF
END LOOP the_loop;
END$$
When I run the stored procedure the error that pops up is "there seems to be some syntax error in your code, please refer to MYSql guide. "
edit:
one more help please how to execute this stored procedure.
There are various minor errors;
You need a parameter list, even if empty for the procedure;
CREATE PROCEDURE matlab.squaring()
The continue handler needs to be right below the other declarations;
DECLARE id_cur CURSOR FOR
SELECT ID, Numb FROM A WHERE EXISTS ( SELECT ID FROM c);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET #finish = TRUE;
You forgot a semicolon;
SET #square= #Numb * #Numb;
You forgot # on the variable usages;
) values ( #ID , #Numb, #square);
You forgot a semicolon on END IF
END IF;
Just as an overview, here's the complete thing updated;
CREATE PROCEDURE matlab.squaring()
BEGIN
DECLARE finish BOOLEAN DEFAULT 0; # <- set up initial conditions
DECLARE square BIGINT(10);
DECLARE ID INT(10);
DECLARE Numb INT (10);
DECLARE id_cur CURSOR FOR
SELECT ID, Numb FROM A WHERE EXISTS ( SELECT ID FROM c);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET #finish = TRUE;
SET #square= #Numb * #Numb;
INSERT INTO B
(
ID ,
Numb ,
square
) values ( #ID , #Numb, #square);
OPEN id_cur;
the_loop : LOOP
FETCH id_cur INTO ID;
IF finish THEN
CLOSE id_cur;
LEAVE the_loop;
END IF;
END LOOP the_loop;
END//
You have missed () after PROCEDURE matlab...
And ; after END IF
Also, HANDLER declaration should be before any executable code and
after CURSOR declaration
Semicolon after SET #square= #Numb * #Numb is needed
So, query should be like this:
DELIMITER $$
CREATE PROCEDURE matlab.squaring ()
BEGIN
DECLARE finish BOOLEAN DEFAULT 0; # <- set up initial conditions
DECLARE square BIGINT(10);
DECLARE ID INT(10);
DECLARE Numb INT (10);
DECLARE id_cur CURSOR FOR
SELECT ID, Numb FROM A WHERE EXISTS ( SELECT ID FROM c);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finish = TRUE;
SET #square= #Numb * #Numb;
INSERT INTO B
(
ID ,
Numb ,
square
) values ( ID , Numb, square);
OPEN id_cur;
the_loop : LOOP
FETCH id_cur INTO ID;
IF finish THEN
CLOSE id_cur;
LEAVE the_loop;
END IF;
END LOOP the_loop;
END$$
Missed parameter brackets and semicolon at endif.
DELIMITER $$
CREATE PROCEDURE squaring()
BEGIN
DECLARE finish BOOLEAN DEFAULT 0; # <- set up initial conditions
DECLARE square BIGINT(10);
DECLARE ID INT(10);
DECLARE Numb INT (10);
DECLARE id_cur CURSOR FOR
SELECT ID, Numb FROM A WHERE EXISTS ( SELECT ID FROM c);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finish = TRUE;
SET #square= #Numb * #Numb;
INSERT INTO B
(
ID ,
Numb ,
square
) values ( ID , Numb, square);
OPEN id_cur;
the_loop : LOOP
FETCH id_cur INTO ID;
IF finish THEN
CLOSE id_cur;
LEAVE the_loop;
END IF;
END LOOP the_loop;
END$$
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 ;
When trying to run this in the SQL window in phpmyadmin the following error is returned..
SQL
DELIMITER $$
DROP FUNCTION IF EXISTS `stock_in_stock_ids` $$
CREATE DEFINER=`root`#`localhost` FUNCTION `stock_in_stock_ids`(_running_total_limit INT, _product_id INT, _block_id INT) RETURNS TEXT
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE _running_qty INT DEFAULT 0;
DECLARE _id INT;
DECLARE _qty INT;
DECLARE _ids TEXT DEFAULT NULL;
DECLARE _cur CURSOR FOR
SELECT id, qty
FROM stock
WHERE block_id=_block_id && type=2 && product_id=_product_id
ORDER BY time DESC, id DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN _cur;
read_loop: LOOP
FETCH _cur INTO _id, _qty;
IF done THEN
SET _ids = '';
LEAVE read_loop;
END IF;
SET _running_qty = _running_qty + _qty;
SET _ids = CONCAT_WS(',', _ids, _id);
IF _running_qty >= _running_total_limit THEN
LEAVE read_loop;
END IF;
END LOOP read_loop;
CLOSE _cur;
RETURN _ids;
END $$
DELIMITER ;
error
#1418 - This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
update (working solution)
SELECT qty, price_cost, #running_total:=#total running_total, #total:=#total+qty total
FROM stock, (SELECT #running_total:=0, #total:=0) vars
WHERE block_id=101 && type=2 && product_id=20
HAVING running_total<=3000
ORDER BY time DESC, id DESC
You want to use a stored procedure but are using a function. There's a difference, you know?
Also I think you don't need a procedure at all, let alone a cursor. Cursors are expensive as hell.
Does this get you what you want?
SELECT * FROM (
SELECT
id,
qty,
#running_total:=#running_total + qty as running_total
FROM stock
, (SELECT #running_total:=0) vars
WHERE block_id=_block_id && type=2 && product_id=_product_id
ORDER BY time DESC, id DESC
) sq
WHERE running_total <= $yourRunningTotalLimit
I was trying use multiple select at one procedure to assign the value of variable.
but i got error like this "Operand should contain 1 column(s)"
this is my code :
DELIMITER $$
DROP PROCEDURE IF EXISTS `bankdb`.`charge` $$
CREATE PROCEDURE `bankdb`.`charge` ()
BEGIN
DECLARE idcust_val INT;
DECLARE balance_val FLOAT;
DECLARE balance_val1 FLOAT;
DECLARE balance_val2 FLOAT;
DECLARE productCd_val VARCHAR(10);
DECLARE productType_val VARCHAR(10);
DECLARE no_more_rows INT DEFAULT 0;
DECLARE num_rows INT DEFAULT 0;
DECLARE col_cur CURSOR FOR
select a.cust_id, a.avail_balance, a.product_cd, p.product_type_cd
from account a, product p
where a.product_cd = p.product_cd;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = 1;
OPEN col_cur;
select FOUND_ROWS() into num_rows;
read_loop: LOOP
IF no_more_rows THEN
CLOSE col_cur;
LEAVE read_loop;
END IF;
FETCH col_cur INTO idcust_val, balance_val, productCd_val, productType_val;
SELECT idcust_val, balance_val, productCd_val;
IF productType_val = 'ACCOUNT' THEN
IF productCd_val = 'SAV' || productCd_val = 'CD' THEN
IF balance_val < 2000 THEN
SELECT (balance_val-10) INTO balance_val;
END IF;
ELSE
SELECT (balance_val+(balance_val*0,05)) INTO balance_val;
END IF;
ELSE
SELECT (balance_val-(balance_val*0,1)) INTO balance_val;
END IF;
/*UPDATE account SET avail_balance = balance_val WHERE account_id = idcust_val;*/
END LOOP read_loop;
END $$
DELIMITER ;
please help!
Change decimal point ',' to '.'
0,05 -> 0.05
0,1 - 0.1