Enhancing MySQL Stored Procedure performance - mysql

i want to enhance performance of following Mysql Stored Procedure.
i am trying to XML with 100 items. and it is Taking almost 90 seconds. and Its too much.
Please check my following SP.
DELIMITER $$
DROP PROCEDURE IF EXISTS `kshitij`.`Insert_date` $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `Insert_date`()
BEGIN
DECLARE itemstart INTEGER default 1;
DECLARE valuestart INTEGER default 1;
DECLARE itemcount INTEGER;
DECLARE valuecount INTEGER;
SET #xml = '<items>
<size>2</size>
<item>
<value columntype="0" columnid="23">Single Line Text_0</value>
<value columntype="1" columnid="24">Multi Line Text_0</value>
<value columntype="2" columnid="25">Number_0</value>
<value columntype="3" columnid="26">Link_0</value>
<value columntype="4" columnid="27">Image_0</value>
<value columntype="5" columnid="28">Date time_0</value>
</item>
TRYING WITH 100 ITEMS.
</items>';
SET itemcount = (SELECT ExtractValue(#xml, 'count(//item)'));
WHILE itemstart < itemcount
DO
SET valuecount = (SELECT ExtractValue(#xml, 'count(/items/item[itemstart]/value)'));
SET valuestart = 1;
WHILE valuestart < valuecount
DO
IF((SELECT ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columntype')) = '0') THEN
INSERT INTO singleline_text(value) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]'));
INSERT INTO sheet_items(c_id, value_id) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columnid'), (SELECT MAX(id) FROM singleline_text));
END IF;
IF((SELECT ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columntype')) = '1') THEN
INSERT INTO multiline_text(value) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]'));
INSERT INTO sheet_items(c_id, value_id) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columnid'), (SELECT MAX(id) FROM multiline_text));
END IF;
IF((SELECT ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columntype')) = '2') THEN
INSERT INTO number(value) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]'));
INSERT INTO sheet_items(c_id, value_id) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columnid'), (SELECT MAX(id) FROM number));
END IF;
IF((SELECT ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columntype')) = '3') THEN
INSERT INTO link(value) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]'));
INSERT INTO sheet_items(c_id, value_id) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columnid'), (SELECT MAX(id) FROM link));
END IF;
IF((SELECT ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columntype')) = '4') THEN
INSERT INTO image(value) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]'));
INSERT INTO sheet_items(c_id, value_id) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columnid'), (SELECT MAX(id) FROM image));
END IF;
IF((SELECT ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columntype')) = '5') THEN
INSERT INTO date_time(value) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]'));
INSERT INTO sheet_items(c_id, value_id) VALUES(ExtractValue(#xml, '/items/item[$itemstart]/value[$valuestart]/#columnid'), (SELECT MAX(id) FROM date_time));
END IF;
SET valuestart = valuestart + 1;
END WHILE;
SET itemstart = itemstart + 1;
end while;
END $$
DELIMITER ;
Thanks.

Related

MySql Stored Procedure out id return null

I hava stored procedure, that insert into adress table, it has 3 in parametrs and 1 out parametr. If I call this procedure out parametr is null
CREATE DEFINER=`root`#`localhost`
PROCEDURE `insert_adress`(
in d varchar(50),
in r varchar(50),
in c varchar(50),
in adress_text varchar(255),
out id int)
BEGIN
declare disc_id int;
declare reg_id int;
declare coun_id int;
if ((select count(*) from district where district.dist like d) <> 0)
then set disc_id := (select id from district where district.dist like d);
else
insert into district(dist) values(d);
set disc_id := (select max(id) from district);
end if;
if ((select count(*) from region where region.reg like r) <> 0)
then set reg_id := (select id from region where region.reg like r);
else
insert into region(reg) values(r);
set reg_id := (select max(id) from region);
end if;
if ((select count(*) from country where country.coun like c) <> 0)
then set coun_id := (select id from country where country.coun like c);
else
insert into country(coun) values(c);
set coun_id := (select max(id) from country);
end if;
insert into adress(district,region,country,adress_text) values(disc_id,reg_id,coun_id,adress_text);
set id := (select max(id) from adress);
END
I call it:
set #id = 0;
call mustaqil.insert_adress('test1', 'test1', 'test1', 'test1', #id);
select #id;
District,Region,Country tables have 'test1' row
I except that, out id, disc_id, reg_id, coun_id should be number, but it is null
P.S : stored procedure inserts row
just change set id := (select max(id) from adress);
to
select max(id) into id from adress;
it should work

This Mysql Trigger get me this error subquery returns more than 1 row

DELIMITER $$
CREATE TRIGGER Product_Trigger
AFTER UPDATE ON PRODUCT
FOR EACH ROW
BEGIN
INSERT INTO AUDITTRAIL
SET activity = 'updated Product',
employeeName = (select (select concat(firstName,' ',LastName) from employee) from userAccount where accountstatus = 1),
employeeID = (select employeeID from userAccount where accountStatus=1),
activityDate = NOW();
END$$
DELIMITER ;

In MySQL stored procedure getting output 1 in count and if I am executing only query then I am getting output 0

SELECT COUNT(id) INTO student_count FROM student_info WHERE roll_no=roll_no and division_id = division_id and institute_id=institute_id and academic_year_id = academic_year;
I am getting student_count = 1
when I am trying to execute stored procedure.
When I am executing direct query as below:
SELECT COUNT(*) AS c FROM student_info WHERE division_id=9 AND institute_id=1 and academic_year_id =11 and roll_no='12617690';
I am getting result 0 which is right. My procedure is:
**CREATE DEFINER = 'root'#'localhost'
PROCEDURE smart_school.create_student(IN academic_year int(11),IN standard_id int(11),IN division_id int(11),IN student_user_id int(11),IN gr_no VARCHAR(20),IN roll_no VARCHAR(50),IN institute_id INT(11),IN maker_id INT(11),OUT create_student_result varchar(20))
BEGIN
DECLARE student_id int;
DECLARE student_count int;
DECLARE semester varchar(10);
DECLARE exit handler for sqlexception
BEGIN
SET create_student_result = "failure";
SELECT #create_student_result;
ROLLBACK;
END;
IF NOT EXISTS (select id from role_user where user_id = student_user_id and role_id = 3 and institute_id=institute_id limit 0,1) THEN
BEGIN
select COUNT(id) INTO student_count from student_info WHERE roll_no=roll_no and division_id = division_id and institute_id=institute_id and academic_year_id = academic_year;
if student_count < 1 then
BEGIN
START TRANSACTION;
insert into student (is_active,user_id,maker_id,caste_id,category_id,created_at,updated_at) values ('1',student_user_id,maker_id,1,1,NOW(),NOW());
SET student_id = LAST_INSERT_ID();
select semester_id into semester from division where institute_id=institute_id and standard_id=standard_id limit 0,1;
insert into student_info (roll_no,is_active,institute_id,student_id,standard_id,semester_id,division_id,academic_year_id,maker_id,created_at,updated_at) values (roll_no,'1',institute_id,student_id,standard_id,semester,division_id,academic_year,maker_id,now(),now());
insert into institute_student (is_active,gr_no,institute_id,student_id,admission_standard_id,admission_year_id,created_at,updated_at) values ('1',gr_no,institute_id,student_id,standard_id,academic_year,now(),now());
insert into role_user (user_id,role_id,institute_id,is_active,joining_date,created_at) values (student_user_id,3,institute_id,'1',now(),now());
COMMIT;
SET create_student_result = "success";
SELECT #create_student_result;
END;
ELSE
BEGIN
SET create_student_result = "duplicate_rollno";
SELECT #create_student_result;
END;
END IF;
END;
ELSE
BEGIN
SET create_student_result = "already_exists";
SELECT #create_student_result;
END;
END IF;
END**

using a variable inside a trigger

I am testing out my trigger and it works well all except i can't seem my variables don't seem to work like they should.
For instance
DELIMITER //
CREATE TRIGGER lestrigger
AFTER INSERT ON examinations
FOR EACH ROW
BEGIN
DECLARE the_last_inserted_id INT ;
DECLARE the_class_id INT;
DECLARE the_year_id INT;
SET the_last_inserted_id = LAST_INSERT_ID();
SET the_class_id = (select examination_class_id from examinations where examination_id = 1);
SET the_year_id = (select examination_class_id from examinations where examination_id = 1);
insert into examination_data (ed_cs_id,ed_examination_id) select cs_id,#the_last_insert_id from class_students where cs_class_id = 1 AND cs_year_id = 1;
END //
DELIMITER ;
In this line
insert into examination_data (ed_cs_id,ed_examination_id) select cs_id,the_last_insert_id from class_students where cs_class_id = 1 AND cs_year_id = 1;
the_last_insert_id is being seen as a column
When i try this,#the_last_insert_id,its not seen as a column but its not working either.I have not tried the rest of my variables.
How am i going to define and use this the_last_inserted_id = LAST_INSERT_ID(); for instance?.
You can set
Select STH into the_last_inserted_id from TBL limit 1;
insert into examination_data (ed_cs_id,ed_examination_id)
select cs_id,the_last_insert_id
from class_students
where cs_class_id = 1 AND cs_year_id = 1;
Edit:
# - You are using without declaring, just seting
Select STH into #new_id from TBL limit 1;
and then
insert into examination_data (ed_cs_id,ed_examination_id)
select cs_id,#the_last_insert_id
from class_students
where cs_class_id = 1 AND cs_year_id = 1;

MySQL stored proc WHILE give only last result

I want to extract a count for every Date between two dates (#sdate,#edate) but it gives me only the count for the last day and not for all days.
How can i output all results? Here is my stored proc.
DELIMITER $$
USE `cmd_storeinfo`$$
DROP PROCEDURE IF EXISTS `test2`$$
CREATE DEFINER=`USER`#`%` PROCEDURE `test2`()
BEGIN
SET #sdate = (DATE_SUB(CURDATE(), INTERVAL 6 MONTH));
SET #edate = (CURDATE());
SET #x='';
SET #Y='';
WHILE #sdate <= #edate DO
SELECT COUNT(*) INTO #y
FROM cmd_storeinfo.strinfo
WHERE LiveDate <= #sdate AND DeinstallDate >= #sdate OR DeinstallDate IS
NULL AND LiveDate IS NOT NULL
AND CHAIN != 1 && CHAIN != 2 && CHAIN != 999
GROUP BY #sdate
SET #x = #sdate;
SET #sdate = (DATE_ADD(#sdate, INTERVAL 1 DAY));
END WHILE;
SELECT #x,#y;
END$$
DELIMITER ;
Thanks for you help.
Daniel
You should try to use temporary table. Here is a nice answer about it.
Something like this could work:
DELIMITER $$
USE `cmd_storeinfo`$$
DROP PROCEDURE IF EXISTS `test2`$$
CREATE DEFINER=`USER`#`%` PROCEDURE `test2`()
BEGIN
CREATE TEMPORARY TABLE tmpTable (currentDate DATE, startDate INT);
SET #sdate = (DATE_SUB(CURDATE(), INTERVAL 6 MONTH));
SET #edate = (CURDATE());
SET #x='';
SET #Y='';
WHILE #sdate <= #edate DO
INSERT INTO tmpTable (currentDate, startDate)
SELECT #sdate, COUNT(*)
FROM cmd_storeinfo.strinfo
WHERE LiveDate <= #sdate AND DeinstallDate >= #sdate OR DeinstallDate IS
NULL AND LiveDate IS NOT NULL
AND CHAIN != 1 && CHAIN != 2 && CHAIN != 999
GROUP BY #sdate
SET #sdate = (DATE_ADD(#sdate, INTERVAL 1 DAY));
END WHILE;
SELECT * FROM tmpTable;
DROP TEMPORARY TABLE IF EXISTS tmpTable;
END$$
DELIMITER ;
You should use Temporary table to store all values.
DELIMITER $$
USE `cmd_storeinfo`$$
DROP PROCEDURE IF EXISTS `test2`$$
CREATE DEFINER=`USER`#`%` PROCEDURE `test2`()
BEGIN
SET #sdate = (DATE_SUB(CURDATE(), INTERVAL 6 MONTH));
SET #edate = (CURDATE());
SET #x='';
SET #Y='';
CREATE TEMPORARY TABLE tmpTable (x datetime,y bigint); -- creating tmp table
WHILE #sdate <= #edate DO
SELECT COUNT(*) INTO #y
FROM cmd_storeinfo.strinfo
WHERE LiveDate <= #sdate AND DeinstallDate >= #sdate OR DeinstallDate IS
NULL AND LiveDate IS NOT NULL
AND CHAIN != 1 && CHAIN != 2 && CHAIN != 999
GROUP BY #sdate
SET #x = #sdate;
insert into tmpTable (x,y) values (#x,#y); -- inserting values
SET #sdate = (DATE_ADD(#sdate, INTERVAL 1 DAY));
END WHILE;
SELECT x,y from tmpTable order by x; -- output temp table results
END$$
DELIMITER ;