I have buffet table and I want to replace an ingredient with another, but my cursor replacing twice, and I get wrong answer.
Note: I'm using MySQL Workbench v 8.0.30
CREATE PROCEDURE cur_snak(in name_snak varchar(20), in old_ingred text,
in new_ingred text)
BEGIN
declare res text;
declare d int default 0;
declare c_id int ;
declare get_cur_ingred cursor for select id from buffet where `name`=name_snak;
declare continue handler for sqlstate '02000'
set d=1;
declare continue handler for sqlstate '23000'
set d=1;
open get_cur_ingred ;
lbl: loop
if d=1 then
leave lbl;
end if;
if not d=1 then
fetch get_cur_ingred into c_id ;
select insert((select ingredients from buffet where id=c_id ),
(select locate(old_ingred,ingredients) from buffet where id=c_id ),
(select length(old_ingred)),new_ingred) into res;
update buffet
set ingredients =res
where id=c_id;
end if;
end loop.
close get_cur_ingred;
END
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.
Why both my variables output NULL? SELECT part of the cursor is working properly.
CREATE PROCEDURE p2()
BEGIN
# Account table
DECLARE accountid INT;
DECLARE accountname VARCHAR(1000);
# 1. cursor finished/done variable comes first
DECLARE done INT DEFAULT 0;
# 2. the curser declaration and select
DECLARE c_account_id_name CURSOR FOR SELECT
accountid,
accountname
FROM temp.test;
# 3. the continue handler is defined last
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = TRUE;
OPEN c_account_id_name;
SET accountid = 0;
SET accountname = '';
read_loop: LOOP
FETCH c_account_id_name
INTO accountid, accountname;
IF done
THEN
LEAVE read_loop;
END IF;
SELECT accountname;
END LOOP;
END;
Variable and select attribute in cursor can't be the same...it's a MySQL bug.
This will work
DROP PROCEDURE IF EXISTS p2;
DELIMITER $$
CREATE PROCEDURE p2()
BEGIN
# Account table
DECLARE v_accountidsome INT; #pay attention
DECLARE v_accountnameelst VARCHAR(1000); #pay attention
# 1. cursor finished/done variable comes first
DECLARE v_done INT DEFAULT FALSE;
# 2. the cursor declaration and select
DECLARE c_account_id_name CURSOR FOR SELECT
accountid, #pay attention
accountname #pay attention
FROM temp.test;
# 3. the continue handler is defined last
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET v_done = TRUE;
OPEN c_account_id_name;
read_loop: LOOP
FETCH c_account_id_name
INTO v_accountidsome, v_accountnameelst;
IF v_done
THEN
LEAVE read_loop;
END IF;
SELECT v_accountidsome;
SELECT v_accountnameelst;
END LOOP;
CLOSE c_account_id_name;
END $$
DELIMITER ;
CALL p2();
Find more here
I created a store procedure to do some insertions, fetch the records of a table and insert it into another table. For that I used cursor (my first use of cursor).
My script below:
CREATE DEFINER=`root`#`localhost` PROCEDURE `tenant_creation`(
IN admin_id int, tenant_name varchar(50),tenant_url varchar(50),
tenant_email varchar(50),tenant_phone varchar(50),first_name varchar(50),
last_name varchar(50),plan_id varchar(50),IN is_available tinyint
)
BEGIN
DECLARE exit handler for sqlexception
BEGIN
ROLLBACK;
END;
DECLARE exit handler for sqlwarning
BEGIN
ROLLBACK;
END;
BEGIN
START TRANSACTION;
#insert Tenant details
Insert into tenant(admin_id,tenant_name,tenant_url,tenant_email,tenant_phone,first_name,last_name,plan_id, is_available)
values(admin_id,tenant_name,tenant_url,tenant_email,tenant_phone,first_name,last_name,plan_id,is_available);
SET #tenant_id = LAST_INSERT_ID();
#create Administrator Group
Insert into user_group(tenant_id,user_group_name,description)
values(#tenant_id,"Administrator","Default Administrator's Group");
SET #group_id = LAST_INSERT_ID();
#Create Default Tenan Admin User
Insert into users(tenant_id,username,`password`,firstname,lastname,email)
values(#tenant_id,"Administrator","$2y$10$AxTjqOxYk6atjDSO2Q4iQOprSvYMnR/jAboqfDYkvC1IG43Rwknw6","Default","Default",tenant_email);
#Attach the user to the group
Set #user_id = LAST_INSERT_ID();
Insert into user_group_relationship(tenant_id,user_group_id,user_id)
values(#tenant_id,#group_id,#user_id);
#create Admin profile
insert into profile(tenant_id,profile_name,description)
values(#tenant_id,"Administrator","Administrator Profile");
#Attach the Admin group to the profile
Set #profile_id = LAST_INSERT_ID();
Insert into profile_group_relationship(tenant_id,group_id,profile_id)
values(#tenant_id,#group_id,#profile_id);
END;
BEGIN
#bind the profile to the available screens
#1 fetch all the modules in system
DECLARE cur CURSOR FOR Select system_screen.screen_id,system_screen.screen_name,module_screen_relationship.module_id
from system_screen
join module_screen_relationship
on module_screen_relationship.screen_id = system_screen.screen_id;
begin
DECLARE done INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
read_loop: LOOP
#Fetch one record from CURSOR and set to some variable(If not found then done will be set to 1 by continue handler)
FETCH cur INTO c_screen_id,c_screen_name,c_module_id;
#If done set to 1 then exit the loop else continue
IF done THEN
LEAVE read_loop;
END IF;
Insert into profile_screen_relationship(tenant_id,profile_id,screen_id,module_id,access_level)
values(#tenant_id,#profile_id,c_screen_id,c_module_id,4);
END LOOP read_loop;
#Closing the cursor
CLOSE cur;
End;
COMMIT;
END;
END
but I only got "Error 1327: Undeclared variable: c_screen_id".
What do you think I am doing wrong?
I believe that you have to declare the variables at the beggining as the official documentation shows:
http://dev.mysql.com/doc/refman/5.7/en/cursors.html
DECLARE a CHAR(16);
DECLARE b, c INT;
....
FETCH cur1 INTO a, b;
FETCH cur2 INTO c;
I'm not an expert with MySQL and I've problems with this Stored Procedure.
I'm trying to do the SP with conditions but I don't know what is wrong here, I have a mistake:
Error Code: 1064. You have an error in your SQL syntax; check the
manual that corresponds to your MySQL server version for the right
syntax to use near 'declare done int default 0; declare continue
handler for sqlstate '02000' set' at line 16
delimiter $$
create procedure getListPrsn(IN idEquipo INT, IN tipo char, IN Puesto INT)
begin
declare varJefe int;
declare eqpSupJefe int;
declare jefeONo cursor for select tblpuesto.PtoLiderEqp from tblequipo
inner join tblpuesto on (tblequipo.EqpID=tblpuesto.PtoEqp)
inner join tblplaza on (tblpuesto.PtoID=tblplaza.PzaPto)
inner join tblpersona on (tblplaza.PzaPrsn=tblpersona.PrsnID)
where tblequipo.EqpID=idEquipo and tblpuesto.PtoID=Puesto;
declare equipoSuperiorDeMiJefe cursor for select tblequipo.EqpEqpSup
from tblequipo
inner join tblpuesto on(tblequipo.EqpID=tblpuesto.PtoEqp)
where tblpuesto.PtoID=Puesto;
if tipo="jefe"
then
declare done int default 0;
declare continue handler for sqlstate '02000' set done=1;
open jefeONo;
begin
repeat
fetch jefeONo into varJefe;
until done end repeat;
end;
close jefeONo;
if varJefe=1
then
declare done int default 0;
declare continue handler for sqlstate '02000' set done=1;
open equipoSuperiorDeMiJefe;
begin
repeat
fetch equipoSuperiorDeMiJefe into eqpSupJefe;
until done end repeat;
end;
close equipoSuperiorDeMiJefe;
call getLider(eqpSupJefe);
else
if varJefe=0
then
call getLider(idEquipo);
end if;
end if;
end if;
end $$
delimiter ;
Problem is in the part as pointed below, where you are trying to declare a local variable inside IF .. ELSE block. You can set the variable inside if .. else block but you should declare them in the beginning
if varJefe=1
then
declare done int default 0; <-- Here
You should declare the variable at the beginning like
create procedure getListPrsn(IN idEquipo INT, IN tipo char, IN Puesto INT)
begin
declare varJefe int;
declare eqpSupJefe int;
declare done int default 0; <-- declare it here
A DECLARE has to be at the beginning of a BEGIN ... END block. You can either move them to the beginning of the procedure (the variable declaration has to be before the cursors, the handler declaration has to be after them):
delimiter $$
create procedure getListPrsn(IN idEquipo INT, IN tipo char, IN Puesto INT)
begin
declare varJefe int;
declare eqpSupJefe int;
declare done int default 0;
declare jefeONo cursor for select tblpuesto.PtoLiderEqp from tblequipo
inner join tblpuesto on (tblequipo.EqpID=tblpuesto.PtoEqp)
inner join tblplaza on (tblpuesto.PtoID=tblplaza.PzaPto)
inner join tblpersona on (tblplaza.PzaPrsn=tblpersona.PrsnID)
where tblequipo.EqpID=idEquipo and tblpuesto.PtoID=Puesto;
declare equipoSuperiorDeMiJefe cursor for select tblequipo.EqpEqpSup
from tblequipo
inner join tblpuesto on(tblequipo.EqpID=tblpuesto.PtoEqp)
where tblpuesto.PtoID=Puesto;
declare continue handler for sqlstate '02000' set done=1;
if tipo="jefe"
then
open jefeONo;
begin
repeat
fetch jefeONo into varJefe;
until done end repeat;
end;
close jefeONo;
if varJefe=1
then
open equipoSuperiorDeMiJefe;
begin
set done = 0;
repeat
fetch equipoSuperiorDeMiJefe into eqpSupJefe;
until done end repeat;
end;
close equipoSuperiorDeMiJefe;
call getLider(eqpSupJefe);
else
if varJefe=0
then
call getLider(idEquipo);
end if;
end if;
end if;
end $$
delimiter ;
or put them after the BEGIN statements before the REPEAT statements:
delimiter $$
create procedure getListPrsn(IN idEquipo INT, IN tipo char, IN Puesto INT)
begin
declare varJefe int;
declare eqpSupJefe int;
declare jefeONo cursor for select tblpuesto.PtoLiderEqp from tblequipo
inner join tblpuesto on (tblequipo.EqpID=tblpuesto.PtoEqp)
inner join tblplaza on (tblpuesto.PtoID=tblplaza.PzaPto)
inner join tblpersona on (tblplaza.PzaPrsn=tblpersona.PrsnID)
where tblequipo.EqpID=idEquipo and tblpuesto.PtoID=Puesto;
declare equipoSuperiorDeMiJefe cursor for select tblequipo.EqpEqpSup
from tblequipo
inner join tblpuesto on(tblequipo.EqpID=tblpuesto.PtoEqp)
where tblpuesto.PtoID=Puesto;
if tipo="jefe"
then
open jefeONo;
begin
declare done int default 0;
declare continue handler for sqlstate '02000' set done=1;
repeat
fetch jefeONo into varJefe;
until done end repeat;
end;
close jefeONo;
if varJefe=1
then
open equipoSuperiorDeMiJefe;
begin
declare done int default 0;
declare continue handler for sqlstate '02000' set done=1;
repeat
fetch equipoSuperiorDeMiJefe into eqpSupJefe;
until done end repeat;
end;
close equipoSuperiorDeMiJefe;
call getLider(eqpSupJefe);
else
if varJefe=0
then
call getLider(idEquipo);
end if;
end if;
end if;
end $$
delimiter ;
I fix my SP
We have to check the declaration order
1.- variables
2.- conditions
3.- cursors
4.- handlers
delimiter $$
create procedure getListPrsn(IN idEquipo INT, IN tipo CHAR, IN Puesto INT)
begin
declare varJefe int;
declare eqpSupJefe int;
declare done int default 0;
case tipo
when "jefe" then
begin
declare jefeONo cursor for select tblpuesto.PtoLiderEqp from tblequipo
inner join tblpuesto on (tblequipo.EqpID=tblpuesto.PtoEqp)
inner join tblplaza on (tblpuesto.PtoID=tblplaza.PzaPto)
inner join tblpersona on (tblplaza.PzaPrsn=tblpersona.PrsnID)
where tblequipo.EqpID=idEquipo and tblpuesto.PtoID=Puesto;
declare continue handler for sqlstate '02000' set done=1;
open jefeONo;
repeat
fetch jefeONo into varJefe;
until done end repeat;
close jefeONo;
set done=0;
if varJefe=1
then
begin
declare equipoSuperiorDeMiJefe cursor for select tblequipo.EqpEqpSup
from tblequipo
inner join tblpuesto on(tblequipo.EqpID=tblpuesto.PtoEqp)
where tblpuesto.PtoID=Puesto;
declare continue handler for sqlstate '02000' set done=1;
open equipoSuperiorDeMiJefe;
repeat
fetch equipoSuperiorDeMiJefe into eqpSupJefe;
until done end repeat;
close equipoSuperiorDeMiJefe;
call getLider(eqpSupJefe);
end;#begin del if varJefe=1
else
if varJefe=0
then
call getLider(idEquipo);
end if;
end if;
end;#begin del case JEFE
end case;
end $$
delimiter ;
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