I'm new to Mysql Stored Procedures.
Tring to return rows in a stored procedure after a LOOP.
Here's my code
BEGIN
DECLARE date_SD date;
DECLARE c_stack CURSOR FOR
select SD from t4 where date(SD) >= "2022-05-01" and date(SD)<= "2022-05-30" group by SD;
DROP TEMPORARY TABLE IF EXISTS final_result;
CREATE TEMPORARY TABLE final_result LIKE templaedb.temp_table;
OPEN c_stack;
read_loop: LOOP
FETCH c_stack INTO date_SD;
INSERT INTO final_result VALUES ('first','140','2022-05-06','','1','2','3','4','5');
INSERT INTO final_result VALUES ('last','500','2022-05-06','','11','12','13','14','15');
END LOOP read_loop;
CLOSE c_stack;
select 'Print Test';
select * from final_result;
END
Select statement at last of the Stored Procedure is not working.
Try this
DECLARE date_SD date;
DECLARE c_stack CURSOR FOR
select SD from t4 where date(SD) >= "2022-05-01" and date(SD)<= "2022-05-30" group by SD;
/* add this*/ DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TEMPORARY TABLE IF EXISTS final_result;
CREATE TEMPORARY TABLE final_result LIKE templaedb.temp_table;
OPEN c_stack;
read_loop: LOOP
FETCH c_stack INTO date_SD;
/* must include*/
IF done = 1 THEN
LEAVE read_loop;
END IF;
/* must include*/
INSERT INTO final_result VALUES ('first','140','2022-05-06','','1','2','3','4','5');
INSERT INTO final_result VALUES ('last','500','2022-05-06','','11','12','13','14','15');
END LOOP read_loop;
CLOSE c_stack;
select * from final_result;
Related
I have created a Trigger after INSERT on the table AcademicYearTermLevel which uses a cursor value fetched from another query. I want to use each cursor value in a while loop and insert rows into table SubjectYearTermLevel.
DROP TRIGGER IF EXISTS after_academicyearterm_insert
DELIMITER $$
CREATE TRIGGER after_academicyearterm_insert
AFTER INSERT
ON AcademicYearTerm
FOR EACH ROW
BEGIN
DECLARE temp INT;
DECLARE subj_done, form_done BOOLEAN DEFAULT FALSE;
DECLARE s_id INT;
DECLARE curSubject CURSOR FOR SELECT subject_id FROM Subject;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET subj_done = TRUE;
SET temp = 1;
OPEN curSubject;
cur_subject_loop: LOOP
FETCH FROM curSubject INTO s_id;
IF subj_done THEN
CLOSE curSubject;
LEAVE cur_subject_loop;
END IF;
WHILE temp <= 6 DO
INSERT INTO SubjectYearTermLevel VALUES (NULL, s_id, NEW.yearTerm_id, temp);
SET temp = temp + 1;
END WHILE
END LOOP cur_subject_loop;
END$$
DELIMITER ;
However the problem is that the cursor only seems to fetch one value from the SELECT query
Silly mistake, I SET temp = 1; outside the FETCH, and hence after the first cursor value, the while loop never ran.
-- SET temp = 1;
OPEN curSubject;
cur_subject_loop: LOOP
FETCH FROM curSubject INTO s_id;
SET temp = 1;
IF subj_done THEN
CLOSE curSubject;
LEAVE cur_subject_loop;
END IF;
1_to_6_temp: WHILE temp <= 6 DO
INSERT INTO SubjectYearTermLevel VALUES (NULL, s_id, NEW.yearTerm_id, temp, -1);
SET temp = temp + 1;
END WHILE 1_to_6_temp;
-- CLOSE curSubject;
END LOOP cur_subject_loop;
Mysql cursor issue?
I have written a stored procedure which will travel's record from one table and insert those into 2-3 different tables
using insert statements.
Problem is that i am checking if record is not exists in table1 then I am inserting record from temptable to table1 ,table2 sequentially
,but the condition is having some problem i don't know it its always going into else part.
Code sample is as follows:
CREATE PROCEDURE `insertData`(In clientNo INT,In usedID INT)
BEGIN
declare mame varchar(100);
declare address varchar(100);
declare city varchar(50);
declare IdentityNO1 varchar(20)
declare cur1 cursor for select * from temptable;
declare continue handler for not found set done=1;
SET #clientNo = clientNO;
SET #userID = userID;
set done = 0;
open cur1;
igmLoop: loop
fetch cur1 into Name,Address,City,IdentityNO1,clientNo;
if done = 1 then leave igmLoop; end if;
//If no record exists in some records table1,table2.
IF ( (SELECT COUNT(*) FROM table1
WHERE IndentityNo=IdentityNo1
AND clientNo=#clientNo) < = 0)
INSERT INTO table1 (Name,IdentityNO) VALUES (name,IdentityNO1);
INSERT INTO table2 (Address,City) VALUES(address,city);
ELSE
INSERT INTO tblexceptional(Name,Address,City,IdentityNo)
VALUES(name,address,city,IdentityNo1);
end loop igmLoop;
close cur1;
END
There is no THEN nor END IF keywords, the procedure cannot compile.
Check this link for proper syntax of IF statement: http://dev.mysql.com/doc/refman/5.7/en/if.html
Use EXIST operator instead of (SELECT count(*)... ) <=0,
read this link to know the reason: http://sqlblog.com/blogs/andrew_kelly/archive/2007/12/15/exists-vs-count-the-battle-never-ends.aspx
IF EXISTS(
SELECT null FROM table1
WHERE IndentityNo=IdentityNo1
AND clientNo=#clientNo
)
THEN
INSERT INTO table1 (Name,IdentityNO) VALUES (name,IdentityNO1);
INSERT INTO table2 (Address,City) VALUES(address,city);
ELSE
INSERT INTO tblexceptional(Name,Address,City,IdentityNo)
VALUES(name,address,city,IdentityNo1);
END IF;
I recommend using some prefixes for procedure arguments and variable names to avoid ambiguity, for example use p_ for parameters and v_ for variables. It's hard to guess, looking at this code, which name is a column name, a variable or a procedure parameter. This can lead to mistakes and errors.
Avoid using SELECT * - this code will fail if someone will change the table structure. Explicitely list required columns in the cursor declaration:
declare cur1 cursor for
select name,Address,City,IdentityNO,clientNo
from temptable;
The corrected procedure might look like this:
CREATE PROCEDURE `insertData`(In p_clientNo INT,In p_usedID INT)
BEGIN
declare v_name varchar(100);
declare v_address varchar(100);
declare v_city varchar(50);
declare v_IdentityNO varchar(20)
declare v_clientNo int
declare cur1 cursor for
select name,Address,City,IdentityNO,clientNo
from temptable;
declare continue handler for not found set done=1;
set done = 0;
open cur1;
igmLoop: loop
fetch cur1 into v_name,v_Address,v_City,v_IdentityNO,v_clientNo;
if done = 1 then leave igmLoop; end if;
//If no record exists in some records table1,table2.
IF EXISTS( SELECT 1 FROM table1
WHERE IndentityNo = v_IdentityNo
AND clientNo = v_clientNo)
INSERT INTO table1 (Name,IdentityNO) VALUES (v_name,v_IdentityNO);
INSERT INTO table2 (Address,City) VALUES(v_address,v_city);
ELSE
INSERT INTO tblexceptional(Name,Address,City,IdentityNo)
VALUES(v_name,v_address,v_city,v_IdentityNo);
END IF;
end loop igmLoop;
close cur1;
END
I have a stored procedure in mysql. In it i am selecting some values from database using following statement ,
select version_id from version where version_name between '1.1' and '1.5'
Now i want to run a loop for all selected values from above statement means suppose above statement returns following row ,
version_id (1,5,3,7) so i want to run a loop for values 1,5,3,7 .
How can i achieve this ?
In MySQL, you need to use Cursor element to loop in values
CREATE PROCEDURE CURSOR_LOOP()
BEGIN
DECLARE C1 CURSOR FOR
select version_id where version_name between '1.1' and '1.5'
OPEN C1;
read_loop: LOOP
FETCH C1 INTO v_ID;
IF done THEN
LEAVE read_loop;
END IF;
-- YOUR ACTION HERE
END LOOP;
CLOSE C1;
-- OTHERS ACTIONS
END;
I have a stored proc which inserts rows from a view with ranks into a temporary table.
The temp table is created before I run a cursor loop that inserted values, and SELECT'ed after the loop is done.
However when I CALL medianMessagesPerWeek(); I get an "Error Code : 1329 No data - zero rows fetched, selected, or processed."
If I create the table as a MYISAM table I can manually select the table and confirm that data has been inserted but the stored proc will still give me nothing.
Am I missing something here?
DELIMITER $$
USE `yongopal_metrics`$$
DROP PROCEDURE IF EXISTS `medianMessagesPerWeek`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `medianMessagesPerWeek`()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE tempJoinWeek, tempActiveWeek, rank INT DEFAULT 0;
DECLARE joinWeek, activeWeek, memberNo, messages INT;
DECLARE cur CURSOR FOR SELECT * FROM cohortMessagesPerMemberPerWeek;
DROP TEMPORARY TABLE IF EXISTS medianMessagesPerWeek;
CREATE TEMPORARY TABLE medianMessagesPerWeek
(
joinWeek INT,
activeWeek INT,
memberNo INT,
messages INT,
rank INT
) ENGINE=MEMORY;
OPEN cur;
read_loop: LOOP
FETCH cur INTO joinWeek, activeWeek, memberNo, messages;
IF done THEN
LEAVE read_loop;
END IF;
IF tempJoinWeek = joinWeek AND tempActiveWeek = activeWeek THEN
SET rank = rank + 1;
ELSE
SET tempJoinWeek = joinWeek;
SET tempActiveWeek = activeWeek;
SET rank = 1;
END IF;
INSERT INTO medianMessagesPerWeek VALUES (joinWeek, activeWeek, memberNo, messages, rank);
END LOOP;
CLOSE cur;
SELECT * FROM medianMessagesPerWeek;
DROP TEMPORARY TABLE IF EXISTS medianMessagesPerWeek;
END$$
DELIMITER ;
EDIT
here is what cohortMessagesPerMemberPerWeek looks like
DELIMITER $$
USE `yongopal_metrics`$$
DROP VIEW IF EXISTS `cohortMessagesPerMemberPerWeek`$$
CREATE ALGORITHM=UNDEFINED DEFINER=`root`#`localhost` SQL SECURITY DEFINER VIEW `cohortMessagesPerMemberPerWeek` AS
SELECT
WEEK(`m`.`regDatetime`,0) AS `joinWeek`,
WEEK(`cd`.`sendDate`,0) AS `activeWeek`,
`m`.`memberNo` AS `memberNo`,
COUNT(0) AS `messages`
FROM (`yongopal`.`chatData` `cd`
JOIN `yongopal`.`members` `m`
ON ((`cd`.`sender` = `m`.`memberNo`)))
GROUP BY WEEK(`m`.`regDatetime`,0),WEEK(`cd`.`sendDate`,0),`m`.`memberNo`
ORDER BY WEEK(`m`.`regDatetime`,0),WEEK(`cd`.`sendDate`,0)$$
DELIMITER ;
Looks like you're missing a not found handler for your cur cursor. This is necessary to set your done boolean to true when the fetch statement no longer returns any rows (and hence you have reached the end of the dataset returned by the cursor declaration).
Give this a try:
DELIMITER $$
USE `yongopal_metrics`$$
DROP PROCEDURE IF EXISTS `medianMessagesPerWeek`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `medianMessagesPerWeek`()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE tempJoinWeek, tempActiveWeek, rank INT DEFAULT 0;
DECLARE joinWeek, activeWeek, memberNo, messages INT;
DECLARE cur CURSOR FOR SELECT * FROM cohortMessagesPerMemberPerWeek;
declare continue handler for not found set done := true;
DROP TEMPORARY TABLE IF EXISTS medianMessagesPerWeek;
CREATE TEMPORARY TABLE medianMessagesPerWeek
(
joinWeek INT,
activeWeek INT,
memberNo INT,
messages INT,
rank INT
) ENGINE=MEMORY;
OPEN cur;
read_loop: LOOP
FETCH cur INTO joinWeek, activeWeek, memberNo, messages;
IF done THEN
LEAVE read_loop;
END IF;
IF tempJoinWeek = joinWeek AND tempActiveWeek = activeWeek THEN
SET rank = rank + 1;
ELSE
SET tempJoinWeek = joinWeek;
SET tempActiveWeek = activeWeek;
SET rank = 1;
END IF;
INSERT INTO medianMessagesPerWeek VALUES (joinWeek, activeWeek, memberNo, messages, rank);
END LOOP;
CLOSE cur;
SELECT * FROM medianMessagesPerWeek;
DROP TEMPORARY TABLE IF EXISTS medianMessagesPerWeek;
END$$
DELIMITER ;
I have a simple insert select which insert _TABLE_B_ data in _TABLE_A_ new row
INSERT INTO _TABLE_A_(_USERNAME_,_ID_)
SELECT _USERNAME_,_ID_
FROM _TABLE_B_
I want to insert a row in a table named _TABLE_C_ each time i insert a row in _TABLE_A_ and add the current inserted _TABLE_C_ id in _TABLE_A_.
i'll try to explain it in an other way :
INSERT INTO _TABLE_A_(_USERNAME_,_ID_,_FOREIGN_ID_)
SELECT B._USERNAME_,B._ID_,C._FOREIGN_ID_
FROM _TABLE_B_ AS B
LEFT JOIN _TABLE_C_ AS C
#Insert a row in _TABLE_C_ to retrieve _FOREIGN_ID_...
I'm searching for a single minimal query which have the INSERT SELECT statement like mine because insert select can loop and i have to loop.
FYI :
I'm in a stored procedure.
I also use prepared statements with dynamic data, and cursors is not suitable for dynamic data select...
I would do all the INSERTs in _TABLE_C_ first and then join it in the INSERT _TABLE_A_ to get the appropriate foreign keys.
If that is not possible, I would use a cursor.
Cursor on _TABLE_B_ & Fetch
INSERT _TABLE_C_
INSERT _TABLE_A_ with Foreign_Id = SCOPE_IDENTITY()
Fetch next
I found a solution.
create a temporary table and add dynamic select statement which retrieve the primary keys (id)
declare a cursor and select this temporary table id ( variables doesn't work but temporary tables do )
execute statement to create temporary table
open the cursor and iterate the inserts
EXAMPLE
BEGIN
DECLARE isDone INT DEFAULT 0;
DECLARE fetchedmemberWhoWillReceiveMailId int;
DECLARE cur1 CURSOR FOR SELECT id FROM memberWhoWillReceiveMail;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET isDone = 1;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET #sexe = VAR_sexe;
SET #event = VAR_eventId;
SET #subject = VAR_subject;
SET #body = VAR_body;
SET #to = VAR_to;
SET #from = VAR_from;
SET #region = VAR_region;
SET #departement = VAR_departement;
SET #age = VAR_age;
SET #baseSqlStatement =' CREATE TEMPORARY TABLE memberWhoWillReceiveMail SELECT e.id FROM TABLE_A as e LEFT JOIN TABLE_B AS a on a.member_id = e.id';
SET #whereSqlStatement= 'WHERE e.is_visible = 1 AND e.member_group_id IN (10,11) ';
IF (#region!='') THEN
SET #whereSqlStatement= CONCAT(#whereSqlStatement,' AND region=',#region);
END IF;
IF (#event !=null ) THEN
SET #whereSqlStatement= CONCAT(#whereSqlStatement,' AND m.event_id !=' ,#eventId);
END IF;
IF (#sexe!=null ) THEN
SET #whereSqlStatement= CONCAT(#whereSqlStatement,' AND e.sexe=',#sexe);
END IF;
SET #baseSqlStatement = CONCAT(#baseSqlStatement,#whereSqlStatement);
START TRANSACTION;
PREPARE stmt1 FROM #baseSqlStatement;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
OPEN cur1;
FETCH cur1 INTO fetchedmemberWhoWillReceiveMailId;
WHILE NOT isDone DO
INSERT INTO conversation(created_at,updated_at)VALUES(now(),now());
INSERT INTO message(created_at,updated_at,from, to, uniqueID) VALUES(now(),now(),#from,fetchedmemberWhoWillReceiveMailId,LAST_INSERT_ID() );
FETCH cur1 INTO fetchedmemberWhoWillReceiveMailId; END WHILE; CLOSE cur1;
COMMIT;
DROP TEMPORARY TABLE IF EXISTS memberWhoWillReceiveMail;
END