Mysql query taking long time when using variable - mysql

SET #acounts = 0;
SET #bcounts = 0;
SET #cur_year = '2015';
SET #userId = "m00087654";
SELECT *, (#acounts :=#acounts+1) as id FROM (
SELECT distinct userId,cid FROM `TABLE`
WHERE user_id = #userId AND ntype = 'parta' AND date_from <> date_to AND YEAR(ndate) = #cur_year
ORDER BY ndate, cid) AS a;
Time taken 1.22 sec
SELECT *, (#acounts :=#acounts+1) as id FROM (
SELECT distinct userId,cid FROM `TABLE`
WHERE user_id = "m00087654" AND ntype = 'parta' AND date_from <> date_to AND YEAR(ndate) = #cur_year
ORDER BY ndate, cid) AS a;
Time taken 0.0022 sec
when i put user_id = #userId then it take more time comparing user_id = "m00087654"
Any clue why taking more 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

Stored procedure is too slow in mysql

I have a routine. But it' s too slow. How can I improve the query?
My records: http://www.sqlfiddle.com/#!9/14cceb/1/0
My query:
CREATE DEFINER = 'root'#'localhost'
PROCEDURE example.ssa()
BEGIN
drop table if exists gps_table;
drop table if exists exam_datas;
CREATE TEMPORARY TABLE gps_table(ID int PRIMARY KEY AUTO_INCREMENT,timei
int,
trun_date_time datetime, tadd_meter int, tin_here int null);
insert into gps_table(timei,trun_date_time,tadd_meter,tin_here) select
imei, run_date_time, add_meter, in_here from example_table;
CREATE TEMPORARY TABLE exam_datas(ID int PRIMARY KEY AUTO_INCREMENT,vimei
int, vbas_run_date_time datetime, vbit_run_date_time datetime, vdifff int);
select tin_here from gps_table limit 1 into #onceki_durum;
select count(id) from gps_table into #kayit_sayisi;
set #i = 1;
set #min_mes = 0;
set #max_mes = 0;
set #frst_id = 0;
set #imei = 0;
set #run_date_time = '0000-00-00 00:00:00';
set #run_date_time2 = '0000-00-00 00:00:00';
myloop: WHILE (#i <= #kayit_sayisi) DO
select tin_here from gps_table where id = #i into #in_here_true;
if (#in_here_true = 1) then
select id,trun_date_time, tadd_meter from gps_table where id = #i into #frst_id,#run_date_time2, #min_mes;
select id from gps_table where id > #frst_id and tin_here =0 order by id asc limit 1 INTO #id;
SET #id = #id-1;
select id, timei, trun_date_time, tadd_meter from gps_table
where id = #id and tin_here =1 limit 1 into #i, #imei, #run_date_time, #max_mes;
if(#i-#frst_id>3) then
set #i:=#i+1;
insert into exam_datas(vimei,vbas_run_date_time,vbit_run_date_time,vdifff) Values (#imei, #run_date_time2, #run_date_time, #max_mes-#min_mes);
SELECT * FROM exam_datas;
SET #asd =1;
elseif 1=1 then
set #i:=#i+1;
End if;
ELSEIF 1=1
THEN SET #i:=#i+1;
End if;
IF (#i = #kayit_sayisi)
THEN set #tamam =1; LEAVE myloop;
END IF;
END WHILE myloop;
select DISTINCT * from exam_datas;
drop table if exists exam_datas;
drop table if exists gps_table;
END
I need: id= 6 first true and id= 11 last_true
firs_trure - last_true = 304-290= 14
id=14 first true and id=18 last_true
firs_true - last_true = 332-324= 8
This routine is too slow.
MySql version is 5.7 and There are 2 milions record in the table.
UPDATE:
Query is here. HERE
Thank you #LukStorms
It's possible to get such results in 1 query.
Thus avoiding a WHILE loop over records.
This example works without using window functions. Just using variables inside the query to calculate a rank. Which is then used to get the minimums and maximums of the groups.
select
imei,
min(run_date_time) as start_dt,
max(run_date_time) as stop_dt,
max(add_meter) - min(add_meter) as diff
from
(
select imei, id, run_date_time, add_meter, in_here,
case
when #prev_imei = imei and #prev_ih = in_here then #rnk
when #rnk := #rnk + 1 then #rnk
end as rnk,
#prev_imei := imei as prev_imei,
#prev_ih := in_here as prev_ih
from example_table t
cross join (select #rnk := 0, #prev_ih := null, #prev_imei := null) vars
order by imei, id, run_date_time
) q
where in_here = 1
group by imei, rnk
having count(*) > 4
order by imei, min(id);
In the procedure such query can be used to fill that final temporary table.
A test on db<>fiddle here

SQL code: adding value to one code but shown in other code as well

could somebody help me with this, please? I was checking answers around the net but still not successful.
I have two codes, code #1:
SELECT subject_note,ticket_id,created_time,status,
UPPER(SUBSTRING(datacenter,1,3)) region
FROM sort_ticket WHERE ticket_type = 1 AND status =0 AND team_type = 1 AND MONTH(FROM_UNIXTIME(closed_date)) = MONTH(NOW())
and YEAR(FROM_UNIXTIME(closed_date)) = YEAR(NOW())
AND
(
-- ASH
owner_id = 812400897
or owner_id = 1392249056
or owner_id = 739243661
or owner_id = 100002941128738
or owner_id = 619251675
or owner_id = 502392893
)
and code #2:
SELECT
subject_note,
cyborg_verify_tries,
ticket_id,
closed_date,
created_time,
status,
UPPER(SUBSTRING(datacenter,1,3)) region
FROM sort_ticket
WHERE ticket_type = 1
AND status =0
AND team_type = 1
and (FROM_UNIXTIME(closed_date)) >= DATE_SUB(now(), INTERVAL 6 MONTH)
AND
(
-- ASH
owner_id = 812400897
or owner_id = 1392249056
or owner_id = 739243661
or owner_id = 100002941128738
or owner_id = 619251675
or owner_id = 502392893
)
Both of these codes creating table and giving me the results what is good.
Problem what I have in here is I have to add manually every NEW "owner_id" into each code.
Is there any way how I could add NEW "owner_id" only into any code and second would be updated automatically? Both info are taken from the same table "sort_ticket".
Thank you for all the help.
You can use an extra table, where you put in the user id's and replace the fixed values with a select on this data:
SELECT
subject_note,
cyborg_verify_tries,
ticket_id,
closed_date,
created_time,
status,
UPPER(SUBSTRING(datacenter,1,3)) region
FROM sort_ticket
WHERE ticket_type = 1
AND status =0
AND team_type = 1
and (FROM_UNIXTIME(closed_date)) >= DATE_SUB(now(), INTERVAL 6 MONTH)
AND
(
-- ASH
select owner_id from newtable
)
same in the other select
You can use an additional table or an additonal view. Use a join to the new table/view in your queries and add new owner_id with an insert in the table or an UNION in the view.
To solve your proble with a view you can do this:
CREATE VIEW v_sort_ticket_owner AS
SELECT 812400897 as owner_id
UNION
SELECT 1392249056 as owner_id
UNION
SELECT 739243661 as owner_id
UNION
SELECT 100002941128738 as owner_id
UNION
SELECT 619251675 as owner_id
UNION
SELECT 502392893 as owner_id
--UNION
--SELECT newnumber as ownder_id
SELECT subject_note,ticket_id,created_time,status,
UPPER(SUBSTRING(datacenter,1,3)) region
FROM sort_ticket st
JOIN v_sort_ticket_owner sto
ON st.owner_id = sto.owner_id
WHERE st.ticket_type = 1 AND st.status =0 AND st.team_type = 1 AND
MONTH(FROM_UNIXTIME(st.closed_date)) = MONTH(NOW())
and YEAR(FROM_UNIXTIME(st.closed_date)) = YEAR(NOW())

Select Status That Last for More Than 1 Second

I have got a problem looks simple, but I could not find the solution.
So, I have got a table with two cols like this:
Time Status
00:00:00.111 Off
00:00:00.222 On
00:00:00.345 On
00:00:01.555 On
00:00:01.666 Off
00:00:02.222 On
00:00:02.422 On
00:00:02.622 Off
00:00:05.888 Off
00:00:05.999 Off
I want to select all statuses of On which lasted for more than 1 second,
in this example, I want the sequence:
00:00:00.222 On
00:00:00.345 On
00:00:01.555 On
Could you guys give me any clue? Many thanks!
A simple GROUP BY and SUM can not do this on your current dataset, so my idea is to add a helper column:
CREATE TABLE someTable(
`time` DATETIME,
status CHAR(3),
helperCol INT
);
The helperCol is an INT and will be set as follows:
CREATE PROCEDURE setHelperCol()
BEGIN
DECLARE finished,v_helperCol INT;
DECLARE status CHAR(3);
DECLARE ts DATETIME;
DECLARE CURSOR st FOR SELECT `time`,status,helperCol FROM someTable WHERE helperCol IS NOT NULL; -- Handy for re-use: No need to go over all data, so you can save the helperCol as permanent value.
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
SELECT #maxVal:=MAX(helperCol) FROM helperCol;
SET finished=0;
SET helperCol=#maxVal;
IF(!helperCol>0) SET helperCol=1;
OPEN st;
FETCH ts,status,v_helperCol FROM st;
WHILE(finished=0) DO
IF(status='Off') v_helperCol=v_helperCol+1;
UPDATE someTable SET helperCol=v_helperCol WHERE `time`=ts; -- Assuming `time` is unique;
FETCH ts,status,v_helperCol FROM st;
END WHILE;
CLOSE st;
END;
Execute the procedure and the result is:
Time Status helperCol
00:00:00.111 Off 2
00:00:00.222 On 2
00:00:00.345 On 2
00:00:01.555 On 2
00:00:01.666 Off 3
00:00:02.222 On 3
00:00:02.422 On 3
00:00:02.622 Off 4
This can now be grouped and processed:
SELECT MAX(`time`)-MIN(`time`) AS diffTime
FROM someTable
WHERE status='ON'
GROUP BY helperCol
HAVING MAX(`time`)-MIN(`time`)>1;
The result of that is (you need to search for the correct datetime functions to apply in the MAX-MIN part):
1.333
Alternative:
You can also process the MAX-MIN in the stored procedure, but that would not be efficiently repeatable as the helperColumn solution is.
SELECT a.time start
, MIN(c.time) end
, TIMEDIFF(MIN(c.time),a.time) duration
FROM
( SELECT x.*, COUNT(*) rank FROM my_table x JOIN my_table y ON y.time <= x.time GROUP BY time ) a
LEFT
JOIN
( SELECT x.*, COUNT(*) rank FROM my_table x JOIN my_table y ON y.time <= x.time GROUP BY time ) b
ON b.status = a.status
AND b.rank = a.rank - 1
JOIN
( SELECT x.*, COUNT(*) rank FROM my_table x JOIN my_table y ON y.time <= x.time GROUP BY time ) c
ON c.rank >= a.rank
LEFT
JOIN
( SELECT x.*, COUNT(*) rank FROM my_table x JOIN my_table y ON y.time <= x.time GROUP BY time ) d
ON d.status = c.status
AND d.rank = c.rank + 1
WHERE b.rank IS NULL
AND d.rank IS NULL
AND a.status = 1
GROUP
BY a.time
HAVING duration >= 1;
Another, faster, method might be along these lines - unfortunately I don't think the data types and functions in my version of MySQL support fractions of a second, so this is probably a little bit wrong (there may also be a logical error)...
SELECT time
, status
, cumulative
FROM
( SELECT *
, CASE WHEN #prev = status THEN #i:=#i+duration ELSE #i:=0 END cumulative
, #prev:=status
FROM
( SELECT x.*
, TIME_TO_SEC(MIN(y.time))-TIME_TO_SEC(x.time) duration
FROM my_table x
JOIN my_table y
ON y.time > x.time
GROUP
BY x.time
) n
ORDER
BY time
) a
WHERE cumulative >= 1
AND status = 1;

fetch no of rows from table 2 with id of table 1

I have some thing to do here with subquery but I am not able to do.
I want the result from a table with a extra field to show to no of results from other table with a column value from table 1.
table1:
CountryId Country ISO2 ISO3
table2:
id noof_country state
I have to retrive noof_country count in table 1 as count field
EDIT
my actual tables are
table 1:
ad_id job_country status delete days_left
table 2:
CountryId Country ISO2 status
I have done query in two phase:
$sql_map = "select distinct c.ISO2, c.Country, a.job_country
from rec_countries c, rec_advert a
where c.status = 1
and DATE(a.modified_date) >= CURDATE() - INTERVAL 30 DAY
and c.ISO2 <> '--'
and c.ISO2 <> ''
and c.CountryId = a.job_country
and a.status = 1
and a.`delete` = 0
and a.days_left >0
";
$res = mysql_query($sql_map);
while($row = mysql_fetch_array($res)){
$jobs_no = count($row['job_country']);
$sql_job = "SELECT COUNT( job_country ) AS jobs_no
FROM rec_advert
WHERE job_country = ".$row['job_country']."
and status = 1
and `delete` = 0
and days_left >0";
$resjob=mysql_query($sql_job);
$rowjob = mysql_fetch_array($resjob);
//here jobs_no is the count of total rows
}
Here I want to do with subquery.
If I read the question right, this should work:
SELECT
CountryId,
Country,
ISO2,
ISO3,
(
SELECT COUNT(DISTINCT noof_country)
FROM table2
WHERE table2.id = table1.CountryId
) AS noof_country_count
FROM table1
It's not immediately clear in your question which column in table1 is a foreign key to which column in table2... or if they are even related that way. If this query doesn't work for you, please clarify your schema.
Based on your updated information, try this:
select distinct c.ISO2, c.Country, a.job_country,
(
select COUNT(a2.job_country)
from rec_advert a2
where a2.job_country = a.job_country
and a2.status = 1
and a2.`delete` = 0
and a2.days_left >0
) as jobs_no
from rec_countries c, rec_advert a
where c.status = 1
and DATE(a.modified_date) >= CURDATE() - INTERVAL 30 DAY
and c.ISO2 <> '--'
and c.ISO2 <> ''
and c.CountryId = a.job_country
and a.status = 1
and a.`delete` = 0
and a.days_left >0