Query runs fast, but stored procedure is slow - Tried multiple things - mysql

I have a stored procedure which queries values from 2 tables (message and message_archived) which contain many data.
CREATE PROCEDURE `get_all_message_report`(IN fromDate TIMESTAMP, IN toDate TIMESTAMP, IN period VARCHAR(15))
BEGIN
DECLARE lfromDate TIMESTAMP;
DECLARE ltoDate TIMESTAMP;
DECLARE lperiod VARCHAR(15);
DECLARE dateFormat VARCHAR(15);
SET lfromDate = fromDate;
SET ltoDate = toDate;
SET lperiod = period;
SET dateFormat = "";
IF lperiod = "monthly"
THEN
SET dateFormat = '%b';
ELSEIF lperiod = "daily"
THEN
SET dateFormat = '%Y-%c-%d';
ELSEIF lperiod = "weekly"
THEN
SET dateFormat = '%x-%v';
END IF;
CREATE TABLE tempMessages(
id bigint(20),
generated_time timestamp,
direction varchar(255),
status varchar(255),
read_status varchar(50),
type varchar(255),
from_number varchar(255),
to_number varchar(255),
INDEX ind (id,generated_time)
);
INSERT INTO tempMessages(id,generated_time,direction,status,read_status,type,from_number,to_number)
SELECT id,generated_time, direction, status, read_status, type, from_number, to_number
FROM (
SELECT id,generated_time, direction, status, read_status, type, from_number, to_number
FROM message WHERE generated_time BETWEEN lfromDate AND ltoDate
union all
SELECT id,generated_time, direction, status, read_status, type, from_number, to_number
FROM message_archived WHERE generated_time BETWEEN lfromDate AND ltoDate
) t;
SELECT
sentMessageTable.date,
IFNULL(sentMessageTable.sentcount, 0) AS sentMessageCount,
IFNULL(newPassMessagesTable.newpassmessagescount, 0) AS newPassMessagesCount,
IFNULL(newReviewMessagesTable.newreviewmessagescount, 0) AS newReviewMessagesCount,
IFNULL(newFailMessagesTable.newfailmessagescount, 0) AS newFailMessagesCount,
IFNULL(respondedPassThreadsTable.respondedpassthreadcount, 0) AS passThreadsRespondedCount,
IFNULL(respondedReviewThreadsTable.respondedreviewthreadcount, 0) AS reviewThreadsRespondedCount,
IFNULL(respondedFailThreadsTable.respondedfailthreadcount, 0) AS failThreadsRespondedCount
FROM
(
(
/* sent message count*/
SELECT
date,
sum(sentcount1) AS sentcount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date,
COUNT(*) AS sentcount1
FROM tempMessages
WHERE direction = 'outgoing' and status in ('SENT','DELIVERED')
GROUP BY date
) t
GROUP BY date
ORDER BY date
) AS sentMessageTable LEFT JOIN
/* new pass messages count */
(
SELECT
date1,
sum(newpassmessagescount1) AS newpassmessagescount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date1,
COUNT(*) AS newpassmessagescount1
FROM tempMessages
WHERE direction='incoming'
AND read_status='UNREAD' AND type='PASS'
GROUP BY date1
) t
GROUP BY date1
ORDER BY date1
)
AS newPassMessagesTable
ON sentMessageTable.date=newPassMessagesTable.date1
LEFT JOIN
/* new review messages count */
(
SELECT
date2,
sum(newreviewmessagescount1) AS newreviewmessagescount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date2,
COUNT(*) AS newreviewmessagescount1
FROM tempMessages
WHERE direction='incoming'
AND read_status='UNREAD' AND type='REVIEW'
GROUP BY date2
) t
GROUP BY date2
ORDER BY date2
)
AS newReviewMessagesTable
ON sentMessageTable.date=newReviewMessagesTable.date2
LEFT JOIN
/* new fail messages count */
(
SELECT
date3,
sum(newfailmessagescount1) AS newfailmessagescount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date3,
COUNT(*) AS newfailmessagescount1
FROM tempMessages
WHERE direction='incoming'
AND read_status='UNREAD' AND type='FAIL'
GROUP BY date3
) t
GROUP BY date3
ORDER BY date3
)
AS newFailMessagesTable
ON sentMessageTable.date=newFailMessagesTable.date3
LEFT JOIN
/* responded pass thread count*/
(
SELECT
date4,
count(*) AS respondedpassthreadcount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date4,
from_number,
to_number,
COUNT(*),
MAX(msg.id) AS maxId
FROM tempMessages msg
GROUP BY date4, msg.from_number, msg.to_number
HAVING maxId IN
(
SELECT max(msg.id)
FROM tempMessages msg
WHERE msg.direction = "outgoing"
GROUP BY DATE_FORMAT(generated_time, dateFormat), msg.from_number, msg.to_number
) AND maxId NOT IN (SELECT MIN(msgSub.id)
FROM tempMessages msgSub
GROUP BY msgSub.from_number, msgSub.to_number
HAVING MIN(msgSub.id) = MAX(msgSub.id))
AND from_number IN ( select msg1.to_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='PASS')
AND to_number IN ( select msg1.from_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='PASS')
) t
GROUP BY date4
ORDER BY date4
) AS respondedPassThreadsTable
ON sentMessageTable.date = respondedPassThreadsTable.date4
LEFT JOIN
/* responded review thread count*/
(
SELECT
date5,
count(*) AS respondedreviewthreadcount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date5,
from_number,
to_number,
COUNT(*),
MAX(msg.id) AS maxId
FROM tempMessages msg
GROUP BY date5, msg.from_number, msg.to_number
HAVING maxId IN
(
SELECT max(msg.id)
FROM tempMessages msg
WHERE msg.direction = "outgoing"
GROUP BY DATE_FORMAT(generated_time, dateFormat), msg.from_number, msg.to_number
) AND maxId NOT IN (SELECT MIN(msgSub.id)
FROM tempMessages msgSub
GROUP BY msgSub.from_number, msgSub.to_number
HAVING MIN(msgSub.id) = MAX(msgSub.id))
AND from_number IN ( select msg1.to_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='REVIEW')
AND to_number IN ( select msg1.from_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='REVIEW')
) t
GROUP BY date5
ORDER BY date5
) AS respondedReviewThreadsTable
ON sentMessageTable.date = respondedReviewThreadsTable.date5
LEFT JOIN
/*responded fail thread count*/
(
SELECT
date6,
count(*) AS respondedfailthreadcount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date6,
from_number,
to_number,
COUNT(*),
MAX(msg.id) AS maxId
FROM tempMessages msg
GROUP BY date6, msg.from_number, msg.to_number
HAVING maxId IN
(
SELECT max(msg.id)
FROM tempMessages msg
WHERE msg.direction = "outgoing"
GROUP BY DATE_FORMAT(generated_time, dateFormat), msg.from_number, msg.to_number
) AND maxId NOT IN (SELECT MIN(msgSub.id)
FROM tempMessages msgSub
GROUP BY msgSub.from_number, msgSub.to_number
HAVING MIN(msgSub.id) = MAX(msgSub.id))
AND from_number IN ( select msg1.to_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='FAIL')
AND to_number IN ( select msg1.from_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='FAIL')
) t
GROUP BY date6
ORDER BY date6
) AS respondedFailThreadsTable
ON sentMessageTable.date = respondedFailThreadsTable.date6
DROP TABLE tempMessages;
END
Instead of creating a normal table i tried using temporary tables
But i can't join a temp table multiple times in same query.
So i tried using normal table which deletes after execution of the sp
but it is also not helping to reduce the loading time.
while executing the query in sp separately i get result in 10-20 seconds
Any solution to reduce loading time ?

Related

Time difference for a particular product

Essentially, I want to find out how much time is spent on a product.
Each product is identified by the model_id and different people may work on
each product. I want the time difference between when the product is being worked on and when there is more than a 5 minute gap.
example table
CREATE TABLE test (id INT, created_at DATETIME, model_id INT, TIMEDIFF DATETIME, TOTALTIME DATETIME)
SELECT '144111', '2019-03-30 11:14:26','301302','',''
UNION
SELECT '144112', '2019-03-30 11:14:33','301302','',''
UNION
SELECT '144113', '2019-03-30 11:14:33','301302','',''
UNION
SELECT '144114', '2019-03-30 11:14:54','301302','',''
UNION
SELECT '144115', '2019-03-30 11:15:35','301302','',''
UNION
SELECT '144116', '2019-03-30 11:22:21','301302','',''
UNION
SELECT '144117', '2019-03-30 11:23:14','301302','',''
UNION
SELECT '144118', '2019-03-30 11:24:24','301302','',''
UNION
SELECT '144119', '2019-03-30 11:25:35','301302','',''
my attempt
WHILE (SELECT COUNT(model_id) FROM portal3_projectsolar.`qat_` WHERE `timediff` IS NULL) > 0 DO #begining of while loop
#min modelid
SET #modelid = (SELECT MIN(model_id) FROM `portal3_projectsolar`.`qat_` WHERE `Timediff` IS NULL);
#set the times
SET #starttime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` a WHERE a.model_id = #modelid AND a.`Timediff` IS NULL ORDER BY a.model_id, a.created_at);
SET #endtime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` a WHERE a.model_id = #modelid AND a.created_at > #starttime AND a.`Timediff` IS NULL ORDER BY a.model_id, a.created_at);
SET #Nexttime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` a WHERE a.model_id = #modelid AND a.created_at > #endtime AND a.`Timediff` IS NULL ORDER BY a.model_id, a.created_at);
# compare the endtime and the nexttime. if nextime is 5 minutes more than endtime then endtime is endtime
WHILE (SELECT DATE_ADD(#endtime,INTERVAL 30 MINUTE) > #Nextdate) DO
SET #Endtime =(SELECT #Nexttime);
SET #Nexttime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` WHERE model_id = #modelid AND created_at > #endtime AND `Timediff` IS NULL ORDER BY model_id, created_at);
END WHILE;
#the time diffrence
SET #timediff = (SELECT TIMESTAMPDIFF(MINUTE, #starttime, #endtime));
SET #startid = (SELECT MIN(id) FROM qat_ WHERE created_at = #starttime);
SET #endid = (SELECT MIN(id) FROM qat_ WHERE created_at = #endtime);
#update the time diff for the id range
UPDATE portal3_projectsolar.`qat_`
SET `timediff` = #timediff
WHERE Created_at = BETWEEN #starttime AND #Endtime;
END WHILE;
The results should show the difference of the start and end in the timediff column and the total time spent for each model_id in the totaltime column

MySQL “subquery returns more than 1 row” error

I am trying to calculate the sum of the products which a client can order based on the product id and the quantity needed.
[CREATE DEFINER=`root`#`localhost` PROCEDURE `calculate_sum`()
BEGIN
SELECT
(SELECT produs_comandat.idComanda
FROM produs_comandat
WHERE produs_comandat.idComanda <= comanda.idComanda) AS idComanda,
(SELECT client.idClient
FROM client
WHERE client.idClient <= comanda.idClient)AS idClient,
(SELECT SUM( produs.pret )
FROM produs_comandat
INNER JOIN produs ON produs.idProdus = produs_comandat.idProdus
WHERE comanda.idComanda <= produs_comandat.idComanda) AS suma
FROM comanda
ORDER BY
(SELECT produs_comandat.cantitate
FROM produs_comandat
WHERE produs_comandat.idComanda <= comanda.idComanda);
END][1]

MySQL Stored procedure says alias is undefined in select statement

I have the following statement, which produces this error. Apparently the alias "R" in the first line of the select statement is not declared, but it's right there at the end of the statement. Anyone have any ideas?
#1327 - Undeclared variable: R
CREATE PROCEDURE `get_series_completion`(IN team1_id INT, IN team2_id INT, IN round_shortname VARCHAR(5))
BEGIN
DECLARE num_games_total, num_games_played INT;
SELECT COUNT(*) INTO num_games_played, R.games_per_series INTO num_games_total
FROM (
SELECT game_id
FROM team_games
WHERE team_id IN (team1_id, team2_id)
GROUP BY game_id
HAVING COUNT(*) = 2
AND SUM(standing = 0) = 0
) AS S, rounds AS R ON R.round_shortname = round_shortname;
SELECT num_games_played/num_games_total;
END$$
You should select all columns before into clause, Your query should be:
SELECT COUNT(*), R.games_per_series INTO num_games_played, num_games_total
FROM (
SELECT game_id
FROM team_games
WHERE team_id IN (team1_id, team2_id)
GROUP BY game_id
HAVING COUNT(*) = 2
AND SUM(standing = 0) = 0
) AS S
LEFT OUTER JOIN rounds AS R ON R.round_shortname = round_shortname;
or
SELECT COUNT(*), R.games_per_series INTO num_games_played, num_games_total
FROM (
SELECT game_id
FROM team_games
WHERE team_id IN (team1_id, team2_id)
GROUP BY game_id
HAVING COUNT(*) = 2
AND SUM(standing = 0) = 0
) AS S, rounds AS R
WHERE R.round_shortname(+) = round_shortname; -- implicit left outer join

calculate values fetched from 2 separate inline select statements

I have a query that I have simplified and written below.
How do I display the time difference of 2 fields that were calculated as 2 separate inline select statements?
SELECT x.name ,
( SELECT data.ts
FROM data
WHERE prim_key = x.prim_key and roll_no ='1'
) **starttime** ,
( SELECT data.ts
FROM woman_data
WHERE prim_key = x.prim_key and roll_no ='10'
) **endtime**
, **TIME_TO_SEC( TIMEDIFF( endtime , starttime)** as timediff // This line does not work.It cannot recognize endtime ans starttime
FROM data x
INNER JOIN y
ON x.prim_key = y.prim_key
ORDER BY x.prim_key
try this:
starttime and endtime are derived columns, you cannot use it in the same select statement..
You have to create a derived table then use these columns the a query outside
select name,starttime,endtime,TIME_TO_SEC( TIMEDIFF( endtime , starttime) as timediff
from(
SELECT x.name ,
( SELECT data.ts
FROM data
WHERE prim_key = x.prim_key and roll_no ='1'
) starttime ,
( SELECT data.ts
FROM woman_data
WHERE prim_key = x.prim_key and roll_no ='10'
) endtime
FROM data x
INNER JOIN y
ON x.prim_key = y.prim_key)a
ORDER BY x.prim_key
The easiest way to change a query to have an "outer-level":
SELECT
name,
starttime,
endtime,
TIME_TO_SEC( TIMEDIFF( endtime , starttime)) as timediff
FROM(
SELECT
x.prim_key,
x.name ,
( SELECT data.ts
FROM data
WHERE prim_key = x.prim_key and roll_no ='1'
) starttime ,
( SELECT data.ts
FROM woman_data
WHERE prim_key = x.prim_key and roll_no ='10'
) endtime
FROM data x
INNER JOIN y
ON x.prim_key = y.prim_key
) n
ORDER BY n.prim_key

Global Variable MySQL

I have this Query:
SELECT
qa_invoices.invoice_clientname,
(
SELECT IFNULL(MIN(qa_returns.discount_code),1)
FROM qa_returns
WHERE qa_returns.invoice_code = qa_invoices.invoice_code
AND qa_returns.discount_code <> 1
) AS discount_code,
qa_users.user_name,
(0.00) AS previous_balance,
(0.00) AS difference_to_be_paid,
(0.00) AS client_credit,
SUM(SubQueryAlias.item_discount) AS invoice_discount,
SUM(SubQueryAlias.item_subtotal) AS invoice_subtotal,
SUM(SubQueryAlias.item_total) AS invoice_total,
DATE_FORMAT(qa_invoices.invoice_date,'%M %e, %Y # %h:%i %p') AS returnlog_date
FROM (
SELECT qa_returns_items.item_code,
qa_returns_items.item_subtotal,
qa_returns_items.item_discount,
qa_returns_items.item_total
FROM qa_returns_items
WHERE returnlog_code = (
SELECT MIN(qa_returns.returnlog_code)
FROM qa_returns
WHERE qa_returns.invoice_code = 1
)
UNION
SELECT qa_returns_residues.item_code,
qa_returns_residues.item_subtotal,
qa_returns_residues.item_discount,
qa_returns_residues.item_total
FROM qa_returns_residues
WHERE returnlog_code = (
SELECT MIN(qa_returns.returnlog_code)
FROM qa_returns
WHERE qa_returns.invoice_code = 1
)
ORDER BY item_code ASC
) AS SubQueryAlias, qa_invoices
LEFT JOIN qa_users USING(user_code)
WHERE SubQueryAlias.item_code NOT IN (
SELECT a.item_code
FROM qa_returns_items a
JOIN qa_returns_residues b
ON b.item_code = a.item_code
WHERE a.returnlog_code = (
SELECT MIN(qa_returns.returnlog_code)
FROM qa_returns
WHERE qa_returns.invoice_code = 1
)
AND b.returnlog_code = (
SELECT MIN(qa_returns.returnlog_code)
FROM qa_returns
WHERE qa_returns.invoice_code = 1
)
)
AND qa_invoices.invoice_code = 1;
The query works fine, but if we look the value invoice_code is set 5 times.
I wonder if there is any way to declare a global variable to assign the same value to all
Sure, you can use user defined variables.
For example:
SET #invoice_code=1;
SELECT MIN(qa_returns.returnlog_code)
FROM qa_returns
WHERE qa_returns.invoice_code = #invoice_code