declaring variable inside mysql stored procedure - mysql

we are trying to declare a variable inside mysql stored procedure that has transaction implemented in it. but it seems to be giving a syntax error :
following is the syntax of the stored procedure:
CREATE PROCEDURE `sp_MarkAppointmentRefferal`(
p_AppId bigint,
p_NewLocation bigint,
p_userId bigint,
p_ReferralReason varchar(500),
p_NewLocationName varchar(100)
)
begin
declare v_OldLocation int default 0;
set v_OldLocation = (select LocationId FROM appointments where iAppID = p_AppId limit 1 );
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
select -1;
END;
START TRANSACTION;
update table
set is_referred = 1,
referred_timestamp = now(),
referral_reason = p_ReferralReason
where iAppID = p_AppId
limit 1;
-- create a new appointment for the new referred location..
insert into appointments
(vAppName, vAppType, dAppDate, vCell, iPatID, iAppStatus, iuserid, iActive,
dInsertDate, iHSID, daily_ticket_no, LocationId, visit_id, encounter_id, ReferredFrom,ReferredOPDName, opd_name )
select vAppName, vAppType, now(), vCell, iPatID, iAppStatus, p_userId,
1, now(), iHSID, fn_GenerateNextAppointmentTicket(now(),p_NewLocation) , p_NewLocation, visit_id, encounter_id+1,
(select LocationId FROM appointments where iAppID = p_AppId limit 1),
(select OPD_Name FROM appointments where iAppID = p_AppId limit 1), p_NewLocationName
FROM appointments
where iAppID = p_AppId limit 1;
select LAST_INSERT_ID();
COMMIT;
end;
the syntax checker is saying that declare command is not valid here.
have also tried to place this inside the transaction clause and similar error shows up ..
any help is appreciated..

All declare statements should be at the top of the stored procedure body. Moving DECLARE EXIT HANDLER before the SET statement should fix the problem.

Related

MySQL migrate data from one table to another

I'm attempting to move data from one table to another, as part of a restructure to the database architecture. I'm using PHPMyAdmin and MySQL to do so.
The SQL is meant to, for each emergency_contacts.id, move e_c.id and e_c.activity_id to activities_emergency_contacts, where the pair will form a composite key to link a contact with an activity.
The following SQL returns an error:
CREATE PROCEDURE dowhile()
BEGIN
SET #cid = (SELECT MIN(`id`) FROM `emergency_contacts`);
SET #aid = (SELECT `activity_id` FROM `emergency_contacts` WHERE `id` = #cid);
WHILE #cid IS NOT NULL DO
INSERT INTO activities_emergency_contacts (activity_id, contact_id)
VALUES (#aid, #cid);
SET #cid = (SELECT MIN(id) FROM emergency_contacts WHERE #cid < id);
SET #aid = (SELECT activity_id FROM emergency_contacts WHERE id = #cid);
END WHILE;
END;
CALL dowhile();
SQL query:
CREATE PROCEDURE dowhile() BEGIN SET #cid = (SELECT MIN(id) FROM
emergency_contacts)
MySQL said:
#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 '' at line 3
I have searched the MySQL specific documentation to try and find any issues with my SET, WHILE, BEGIN/END, INSERT, CREATE - just about every line. I'm unsure how to proceed. Any advice would be greatly appreciated.
EDIT: I missed a closing bracket inside the WHILE on SELECT MIN (id), however I've fixed this and am still getting the exact same issue.
EDIT: The issue was that I was not using DELIMITER. Correct SQL:
DELIMITER $$
CREATE PROCEDURE dowhile()
BEGIN
SET #cid = (SELECT MIN(`id`) FROM `emergency_contacts`);
SET #aid = (SELECT `activity_id` FROM `emergency_contacts` WHERE `id` = #cid);
WHILE #cid IS NOT NULL DO
INSERT INTO activities_emergency_contacts (activity_id, contact_id) VALUES (#aid, #cid);
SET #cid = (SELECT MIN(id) FROM emergency_contacts WHERE #cid < id);
SET #aid = (SELECT activity_id FROM emergency_contacts WHERE id = #cid);
END WHILE;
END$$
DELIMITER ;
CALL dowhile();

1172 - Result consisted of more than one row in mysql

How can I solve this problem (Result consisted of more than one row in mysql)
DROP PROCEDURE IF EXISTS `doMarksApplication`;
CREATE PROCEDURE `doMarksApplication`(
in kuser varchar(20),
out idpro int(11))
SP:BEGIN
declare no_more_rows int default FALSE;
declare total_marks decimal(10,2) default 0;
declare idfor int(11) default 0;
declare sskod int(5) default getCurSession();
declare bdata int(5) default 0;
declare nopmh varchar(20);
# Data PB [Permohonan Baru] DM [Proses Pemarkahan]
declare cur1 cursor for
select ind_nopmh from pinduk
left join pprses on pro_nopmh = ind_nopmh
where ind_sskod = sskod and
concat(pro_stats,pro_statp) in ('PB','DM') and
not exists (select mar_idnum from pmrkah where mar_nopmh = ind_nopmh)
order by ind_nopmh;
declare continue handler for not found set no_more_rows = TRUE;
begin
select count(ind_nopmh) into bdata
from pinduk
left join pprses on pro_nopmh = ind_nopmh
where ind_sskod = sskod and
concat(pro_stats,pro_statp) in ('PB','DM') and
not exists (select mar_idnum from pmrkah where mar_nopmh = ind_nopmh);
end;
begin
select count(for_idnum) into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg;
end;
if idfor = 1 and sskod <> 0 then
begin
select for_idnum into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg;
end;
begin
insert into pprmar
(pma_tkmla,pma_msmla,pma_puser,pma_sskod,pma_idfor,pma_bdata)
values
(curdate(),curtime(),kuser,sskod,idfor,bdata);
end;
begin
select last_insert_id() into idpro;
end;
open cur1;
LOOP1:loop
fetch cur1 into nopmh;
if no_more_rows then
close cur1;
leave LOOP1;
end if;
begin
call getMarksAnakPerak(nopmh,#total_perak);
call getMarksAkademik(nopmh,#total_akdmk);
call getMarksSosioekonomi(nopmh,#total_sosio);
end;
set total_marks = #total_perak + #total_akdmk + #total_sosio;
begin
insert into pmrkah
(mar_idpro,mar_nopmh,mar_idfor,mar_perak,mar_akdmk,mar_sosio,mar_total)
values
(idpro,nopmh,idfor,#total_perak,#total_akdmk,#total_sosio,total_marks);
end;
begin
update pprses
set pro_stats = 'D',
pro_statp = 'M',
pro_tkmsk = curdate(),
pro_msmsk = curtime(),
pro_kuser = kuser
where pro_nopmh = nopmh;
end;
end loop;
begin
update pprmar
set pma_tktmt = curdate(),
pma_mstmt = curtime()
where pma_idnum = idpro;
end;
end if;
END;
i have been programming in mysql for 15 years and this is easily the most confusing stored procedure i have ever seen.
None the less, one possible place for your issue is here
select for_idnum into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg;
I know it does not seem to be the reason but without knowing the content of the other three stored procedures you are calling this is the only candidate. You should add a limit 1 to it, and to every select into statement that reads from a table (i.e. not a sum() or a count() etc...) as that would always have the potential to cause the error you are seeing.
select for_idnum into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg limit 1;
In addition, you should comment out the three stored procedure calls and see if the error goes away. My guess is that the issue is one of those stored procedures due to a select into similar to above has more than one row in the result set but does not use limit 1 and does not filter properly.

How to find problems in MySQL stored procedure?

I have the following stored procedure:
DELIMITER $$
CREATE DEFINER=`195414_py82740`#`%` PROCEDURE `getUserMail`(inUserId INT)
BEGIN
DECLARE done INT default 0;
DECLARE tmpMailId INT default -1;
DECLARE tmpFromUserId INT default -1;
DECLARE cursor1 cursor for select id from mail WHERE toUserId=inUserId OR fromUserId=inUserId ORDER BY sentDate desc;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TEMPORARY TABLE IF EXISTS temp_userMail;
CREATE TEMPORARY TABLE temp_userMail LIKE mail;
OPEN cursor1;
REPEAT
FETCH cursor1 INTO tmpMailId;
SET tmpFromUserId = IF ((SELECT fromUserId FROM mail WHERE id=tmpMailId)=inUserId, (SELECT toUserId FROM mail WHERE id=tmpMailId), (SELECT fromUserId FROM mail WHERE id=tmpMailId));
IF EXISTS(SELECT id FROM temp_userMail WHERE fromUserId=tmpFromUserId || toUserId=tmpFromUserId) THEN
SET tmpMailId = 0;
ELSE
INSERT INTO temp_userMail
(`id`,
`fromUserId`,
`toUserId`,
`sentDate`,
`readDate`,
`message`,
`fromUserNickName`,
`toUserNickName`,
`subject`,
`fromUserDeleted`,
`toUserDeleted`)
SELECT
(m1.id,
m1.fromUserId,
m1.toUserId,
m1.sentDate,
m1.readDate,
m1.message,
m1.fromUserNickName,
m1.toUserNickName,
m1.subject,
m1.fromUserDeleted,
m1.toUserDeleted)
FROM mail m1
WHERE m1.id=tmpMailId;
END IF;
UNTIL(done = 1)
END REPEAT;
CLOSE cursor1;
SELECT * FROM temp_userMail ORDER BY sentDate DESC;
END
The SP is saved successfully but when running it I get the cryptic exception
Error Code: 1241: Operand should contain 1 column(s).
I know what the error means but there is no line nr so I have no idea where to look for the problem?
Remove brackets from Your SELECT subquery
dont use
SELECT (id, ... m1.toUserDeleted) ...
use
SELECT id, ... m1.toUserDeleted ...

Slope-One recommender implementation using mysql stored procedure

I am trying to implement Slop-One recommender using mysql stored procedure, the query runs okay and doesn't give any error. But it is not inserting/updating the 'dev' table.
The structure of tables are:
rating (user_id, article_id, rating_value, date)
dev (article1_id, article2_id, count, sum)
The 'dev' table has joint primary key (article1_id, article2_id). The sql for my procedure is as follows:
DELIMITER $$
CREATE PROCEDURE update_matrix(IN user INT(11), IN article INT(11), IN rating TINYINT(1))
BEGIN
DECLARE article_id2 INT(11);
DECLARE rating_diff TINYINT(1);
DECLARE done TINYINT(1) DEFAULT 0;
DECLARE mycursor CURSOR FOR
SELECT DISTINCT article_id, (rating - rating_value)
FROM rating
WHERE user_id = user AND article_id != article;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN mycursor;
FETCH mycursor INTO article_id2, rating_diff;
WHILE(!done) DO
INSERT INTO dev (`article1_id`, `article2_id`, `count`, `sum`)
VALUES (article, article_id2, 1, rating_diff)
ON DUPLICATE KEY UPDATE count = count + 1, sum = sum + rating_diff;
INSERT INTO dev (`article1_id`, `article2_id`, `count`, `sum`)
VALUES (article_id2, article, 1, -rating_diff)
ON DUPLICATE KEY UPDATE count = count + 1, sum = sum - rating_diff;
FETCH mycursor INTO article_id2, rating_diff;
END WHILE;
CLOSE mycursor;
END$$
DELIMITER ;

Having trouble doing multiple cursors in a MySQL stored procedure

I'm writing a store procedure to create two temporary tables do an union select of the two.
When using either first or second cursor alone with the other commented the procedure works,
but when I run the query to create the procedure with the 2 cursors, it fails.i've changed the code to reflect Ike Walker's suggestion.
Here is the script:
DELIMITER //
DROP PROCEDURE IF EXISTS joinemailsmsdailygraph//
CREATE PROCEDURE joinemailsmsdailygraph(IN previousDay VARCHAR(20), IN today VARCHAR(20))
READS SQL DATA
BEGIN
DECLARE hours INT;
DECLARE sms INT;
DECLARE email INT;
DECLARE smsdone INT DEFAULT 0;
DECLARE emaildone INT DEFAULT 0;
DECLARE cursorsms CURSOR FOR SELECT HOUR(sm.date_created) AS `HOUR OF DAY`, COUNT(*) AS smscount
FROM sms_message_delivery smd
JOIN sms_message sm ON sm.sms_message_id = smd.sms_message_id
WHERE DATE(sm.date_created) >= DATE(previousDay) AND DATE(sm.date_created) < DATE(today)
GROUP BY HOUR(sm.date_created);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET smsdone =1;
DECLARE cursoremail CURSOR FOR SELECT HOUR(em.date_created) AS `HOUR OF DAY`, COUNT(*) AS emailcount
FROM email_message_delivery emd
LEFT JOIN email_message em ON emd.email_message_id=em.email_message_id
WHERE DATE(em.date_created) >= DATE(previousDay) AND DATE(em.date_created) < DATE(today)
GROUP BY HOUR(em.date_created);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET emaildone =1;
DROP TEMPORARY TABLE IF EXISTS tempsms;
CREATE TEMPORARY TABLE tempsms (hours_day INT, sms_count INT, email_count INT);
OPEN cursorsms;
sms_loop: LOOP
FETCH cursorsms INTO hours , sms;
IF smsdone = 1 THEN
LEAVE sms_loop;
END IF;
INSERT INTO tempsms (hours_day, sms_count) VALUES (hours, sms);
END LOOP sms_loop;
CLOSE cursorsms;
DROP TEMPORARY TABLE IF EXISTS tempemail;
CREATE TEMPORARY TABLE tempemail (hours_day INT , sms_count INT , email_count INT);
OPEN cursoremail;
email_loop: LOOP
FETCH cursoremail INTO hours, email;
IF emaildone=1 THEN
LEAVE email_loop;
END IF;
INSERT INTO tempemail(hours_day, email_count) VALUES(hours, email);
END LOOP email_loop;
CLOSE cursoremail;
SELECT hours_day, sms_count , email_count FROM tempsms
UNION
SELECT hours_day, sms_count, email_count FROM tempemail;
END//
DELIMITER;
it gives this as error
Query : CREATE PROCEDURE joinemailsmsdailygraph(IN previousDay VARCHAR(20), IN today VARCHAR(20)) READS SQL DATA BEGIN DECLARE hours INT...
Error Code : 1338
Cursor declaration after handler declaration
Execution Time : 00:00:00:000
Transfer Time : 00:00:00:000
Total Time : 00:00:00:000
ive tried putting both continue handlers at the end of all declare section but it complains about declare block overlapping or so.
Can you please tell me what I'm doing wrong? Thanks for reading.
Why are you using cursors ? You could easily do this without a tmp table also by just using a union.
drop procedure if exists join_email_sms_daily_graph;
delimiter #
create procedure join_email_sms_daily_graph
(
in previousDay varchar(20),
in today varchar(20)
)
begin
create temporary table tmp
(
hours_day int unsigned,
sms_count int unsigned default 0,
email_count int unsigned default 0
)engine=memory;
insert into tmp (hours_day, sms_count)
select
hour(sm.date_created) as hours_day,
count(*) AS sms_count
from
sms_message_delivery smd
join sms_message sm ON sm.sms_message_id = smd.sms_message_id
where
date(sm.date_created) >= date(previousDay) and date(sm.date_created) < date(today)
group by
hour(sm.date_created);
insert into tmp (hours_day, email_count)
select
hour(em.date_created) as hours_day,
count(*) AS email_count
from
email_message_delivery emd
left join email_message em ON emd.email_message_id=em.email_message_id
where
date(em.date_created) >= date(previousDay) and date(em.date_created) < date(today)
group by
hour(em.date_created);
select * from tmp;
drop temporary table if exists tmp;
end#
delimiter;
You need to declare all of the cursors up front, before the logic of your procedure begins.
If you do things in this order it should work:
DECLARE variables
DECLARE cursors
DECLARE handlers
...
logic