MySql - calculate time difference for multiple rows - mysql

I have a table with manufacturing assembly data, including timestamps. I'm trying to determine the average interval in minutes between 'job' starts.
My query that returns the id and time looks like:
select job_id, job_started from JobTable where job_started >= '2016-07-01' and job_started <= '2016-07-31';
I'm looking for output that would be the difference in time between each row:
15
18
21
14
13

Get average interval in seconds:
select (to_seconds(max(job_started)) - to_seconds(min(job_started))) / (count(*) - 1) as average_interval_seconds
from JobTable
where date(job_started) >= '2016-07-01'
and date(job_started) <= '2016-07-31'
;
Get all intervals in seconds:
select to_seconds((
select t2.job_started
from JobTable t2
where t2.job_started > t1.job_started
and date(t2.job_started) <= '2016-07-31'
limit 1
)) - to_seconds(t1.job_started) as interval_seconds
from JobTable t1
where date(t1.job_started) >= '2016-07-01'
and date(t1.job_started) <= '2016-07-31'
and t1.job_started <> (
select job_started
from JobTable
where date(job_started) <= '2016-07-31'
order by job_started desc
limit 1
)
;
http://sqlfiddle.com/#!9/1f8dc3/2

Related

Combine 2 similar queries with different time ranges into 1 instead of using UNION ALL

I am using MySQL 5.7 and I need to do queries from a table like
order_id fee created_time
111 10 2020-11-16
222 90 2020-11-01
333 300 2000-10-22
The results should be the total income of last 1 day(yesterday) and last 30 days, like
date_range revenue
1 10
30 400
The column date_range is the last X day before now and I can do this use 'union all':
SELECT 1 AS date_range, SUM(fee) FROM test
WHERE created_time >= SUBDATE(CURRENT_DATE, 1) AND created_time < CURRENT_DATE
UNION ALL
SELECT 30 AS date_range, SUM(fee) FROM test
WHERE created_time >= SUBDATE(CURRENT_DATE, 30) AND created_time < CURRENT_DATE
The queries are quite similar and is it possible to combine them into ONE query instead of using union all?
CREATE TABLE:
CREATE TABLE test (
order_id INT,
fee INT,
created_time DATETIME
)
INSERT VALUES:
INSERT INTO test VALUES (111,10,'2020-11-16'),(222,90,'2020-11-01'),(333,300,'2020-10-22')
SELECT date_range, SUM(fee)
FROM test
CROSS JOIN (SELECT 1 date_range UNION ALL SELECT 30) date_ranges
WHERE created_time >= CURRENT_DATE - INTERVAL date_range DAY
AND created_time < CURRENT_DATE
GROUP BY date_range
UPDATE
You may improve the performance additionally while creating date-generated subquery with interval borders, not interval lengths:
SELECT DATEDIFF(CURRENT_DATE, date_range) date_range, SUM(fee)
FROM test
CROSS JOIN (SELECT CURRENT_DATE - INTERVAL 1 DAY date_range
UNION ALL
SELECT CURRENT_DATE - INTERVAL 30 DAY) date_ranges
WHERE created_time >= date_range
AND created_time < CURRENT_DATE
GROUP BY date_range
DEMO
You can try using case when:
https://dev.mysql.com/doc/refman/5.7/en/case.html
select date_range, sum(fee)
from (
select
case
when created_time between subdate(current_date, 1) and current_date then 1
when created_time between subdate(current_date, 30) and current_date then 30
end case date_range,
fee
from test) t
where date_range is not null
group by date_range

How to fix my query ? I get a message "the target table is not updatable"

I am trying to update the new_table with the query below.
Unfortunately I get a warning The target table n2 of the UPDATE is not updatable. How can I fix this?
UPDATE new_table n
JOIN (SELECT hash,
visits,
first_visit,
last_visit,
Datediff(last_visit, first_visit) AS date_diff,
( Datediff(last_visit, first_visit) / visits ) AS diafora
FROM new_table
WHERE Date(first_visit) >= Date_sub(Curdate(), INTERVAL 15 day)
AND Date(last_visit) >= Date_sub(Curdate(), INTERVAL 7 day)
AND visits > 1
HAVING date_diff > 0) AS n2
ON n2.hash = n.hash
SET n.diafora = n2.visits_frequency
UPDATE
the visits_frequency is a column in the new_table. The diafora is calculated and the visits_frequence must take its value.
There is no visits_frequency field on n2 table. Where is this field coming from? Is it calculated or maybe you forgot it in the select? If it comes from select, you could try:
UPDATE new_table n
JOIN (SELECT hash,
visits,
visits_frequency,
first_visit,
last_visit,
Datediff(last_visit, first_visit) AS date_diff,
( Datediff(last_visit, first_visit) / visits ) AS diafora
FROM new_table
WHERE Date(first_visit) >= Date_sub(Curdate(), INTERVAL 15 day)
AND Date(last_visit) >= Date_sub(Curdate(), INTERVAL 7 day)
AND visits > 1
HAVING date_diff > 0) AS n2
ON n.hash = n2.hash
SET n.diafora = n2.visits_frequency
Considering you want n.visit_frequency to take the value of n2.diafora calculation, try the following:
UPDATE new_table n
JOIN (SELECT hash,
visits,
visits_frequency,
first_visit,
last_visit,
Datediff(last_visit, first_visit) AS date_diff,
( Datediff(last_visit, first_visit) / visits ) AS diafora
FROM new_table
WHERE Date(first_visit) >= Date_sub(Curdate(), INTERVAL 15 day)
AND Date(last_visit) >= Date_sub(Curdate(), INTERVAL 7 day)
AND visits > 1
HAVING date_diff > 0) AS n2
ON n.hash = n2.hash
SET n.visits_frequency = n2.diafora

How to limit query results by a percentage of the total number of results in MySQL?

The below mysql question returns only the 10 first rows. How can I limit the them to 10% of all?
SELECT page,
poso,
diff
FROM (SELECT page,
Count(*) AS poso,
( Sum(Date(timestamp) = Curdate()) - Sum(
Date(timestamp) = Date_sub(Curdate(),
INTERVAL 1 day)) )
diff
FROM `behaviour`
WHERE Date(timestamp) >= Date_sub(Curdate(), INTERVAL 1 day)
GROUP BY page
ORDER BY ( Sum(Date(timestamp) = Curdate()) - Sum(
Date(timestamp) = Date_sub(Curdate(),
INTERVAL 1 day))
) DESC
LIMIT 10) AS u
ORDER BY diff DESC
Adapted from the answer to the duplicate question:
SELECT page,
poso,
diff
FROM (
SELECT *,
#counter := #counter + 1 AS counter
FROM (select #counter:=0) AS initvar,
(SELECT page,
Count(*) AS poso,
( Sum(Date(timestamp) = Curdate()) - Sum(
Date(timestamp) = Date_sub(Curdate(),
INTERVAL 1 day)) )
diff
FROM `behaviour`
WHERE Date(timestamp) >= Date_sub(Curdate(), INTERVAL 1 day)
GROUP BY page
ORDER BY ( Sum(Date(timestamp) = Curdate()) - Sum(
Date(timestamp) = Date_sub(Curdate(),
INTERVAL 1 day))
) DESC) AS u
) AS v
WHERE counter <= 10/100 * #counter
ORDER BY diff DESC;
Demo here: http://rextester.com/JKMBZR62923

Mysql - get results from complex criteria

I have database with statistics over a number of websites and I'm currently having an issue with a rather complex query that I have no idea how to do (or if it's even possible).
I have 2 tables: websites and visits. The former is a list of all websites and their properties, while the former is a list of each user's visit on a specific website.
The program I'm making is supposed to fetch websites that need to be "scanned". The interval between each scan for each site depends on the websites total number of visits for the last 30 days. Here is a table with the intended scan-interval:
The tables have the following structure:
Websites
Visits
What I want is a query that returns the websites that are either at or past their individual update deadline (can be seen from the last_scanned column).
Is this easily doable in a single query?
Here's something you can try:
SELECT main.*
FROM (
SELECT
w.web_id,
w.url,
w.last_scanned,
(SELECT COUNT(*)
FROM visits v
WHERE v.web_id = w.web_id
AND TIMESTAMPDIFF(DAY,v.added_on, NOW()) <=30
) AS visit_count,
TIMESTAMPDIFF(HOUR,w.last_scanned, NOW()) AS hrs_since_update
FROM websites w
) main
WHERE
(CASE
WHEN visit_count >= 0 AND visit_count <= 10 AND hrs_since_update >= 4320 THEN 1
WHEN visit_count >= 11 AND visit_count <= 100 AND hrs_since_update >= 2160 THEN 1
WHEN visit_count >= 101 AND visit_count <= 500 AND hrs_since_update >= 1080 THEN 1
WHEN visit_count >= 501 AND visit_count <= 1000 AND hrs_since_update >= 720 THEN 1
WHEN visit_count >= 1001 AND visit_count <= 2000 AND hrs_since_update >= 360 THEN 1
WHEN visit_count >= 2001 AND visit_count <= 5000 AND hrs_since_update >= 168 THEN 1
WHEN visit_count >= 5001 AND visit_count <= 10000 AND hrs_since_update >= 72 THEN 1
WHEN visit_count >= 10001 AND hrs_since_update >= 24 THEN 1
ELSE 0
END) = 1;
Here's the fiddle demo: http://sqlfiddle.com/#!9/1f671/1
First, I would make a subquery to get the visit counts from the visits table for each distinct web_id. Then, LEFT OUTER JOIN the websites table to this subquery. You can then query the result for each possible condition in your visits-to-update-frequency table, like so:
SELECT websites.* FROM websites
LEFT OUTER JOIN (
SELECT visits.web_id, COUNT(*) AS visits_count FROM visits GROUP BY visits.web_id
) v ON v.web_id = websites.web_id
WHERE
(v.visits_count <= 10 AND websites.last_scanned <= DATE_SUB(NOW(), INTERVAL 4320 HOUR)) OR
(v.visits_count BETWEEN 11 AND 100 AND websites.last_scanned <= DATE_SUB(NOW(), INTERVAL 2160 HOUR)) OR
(v.visits_count BETWEEN 101 AND 500 AND websites.last_scanned <= DATE_SUB(NOW(), INTERVAL 1080 HOUR)) OR
(v.visits_count BETWEEN 501 AND 1000 AND websites.last_scanned <= DATE_SUB(NOW(), INTERVAL 720 HOUR)) OR
(v.visits_count BETWEEN 1001 AND 2000 AND websites.last_scanned <= DATE_SUB(NOW(), INTERVAL 360 HOUR)) OR
(v.visits_count BETWEEN 2001 AND 5000 AND websites.last_scanned <= DATE_SUB(NOW(), INTERVAL 168 HOUR)) OR
(v.visits_count BETWEEN 5001 AND 10000 AND websites.last_scanned <= DATE_SUB(NOW(), INTERVAL 72 HOUR)) OR
(v.visits_count > 10000 AND websites.last_scanned <= DATE_SUB(NOW(), INTERVAL 24 HOUR));
Just an improvment on #morgb query, using a table for visit count ranges
SQL FIDDLE DEMO
create table visitCount (
`min` bigint(20),
`max` bigint(20),
`frequency` bigint(20)
);
SELECT main.*
FROM (
SELECT
w.web_id,
w.url,
w.last_scanned,
(SELECT COUNT(*)
FROM visits v
WHERE v.web_id = w.web_id
AND TIMESTAMPDIFF(DAY,v.added_on, NOW()) <=30
) AS visit_count,
TIMESTAMPDIFF(HOUR,w.last_scanned, NOW()) AS hrs_since_update
FROM websites w
) main inner join
visitCount v on visit_count between v.min and v.max
WHERE
main.hrs_since_update > v.frequency

join 5 mysql queries

Hi I have below 5 mysql queries, i want to see output of all queries in by executing a single query.
please let me know how can i join all these queries.
1.
select sum(msu)
from wgr_raw
where dt
between '2013-11-01' and '2013-11-07';
2.
select *
from wgr_raw
where dt
between '2013-11-01' and '2013-11-07'
order by dt;
3.
select admin,sum(msu)
from wgr_raw
where dt
between '2013-11-01' and '2013-11-07'
group by admin;
4.
SELECT admin, sum(msu)
from wgr_raw
where dt
between '2013-11-01' and '2013-11-07'
group by admin
order by msu desc
limit 25;
Select ADMIN1,WEEK1,WEEK2,WEEK3,
(((WEEK3-WEEK2)/WEEK2)*100) as percentage_change,
(WEEK3-WEEK2) as MSU_Difference
from
((select admin as ADMIN1, sum(msu) as WEEK1
from wgr_raw
where dt >= date_sub(date('2013-11-01'),
INTERVAL 25 DAY) and dt < date_sub(date('2013-11-07'),
INTERVAL 18 DAY)
group by admin
order by WEEK1) as q1,
(select admin as ADMIN2, sum(msu) as WEEK2
from wgr_raw
where dt >= date_sub(date('2013-11-01'),
INTERVAL 18 DAY) and dt < date_sub(date('2013-11-07'),
INTERVAL 11 DAY)
group by admin
order by WEEK2) as q2,
(select admin as ADMIN3, sum(msu) as WEEK3
from wgr_raw where dt >= date_sub(date('2013-11-01'),
INTERVAL 11 DAY) and dt < date_sub(date('2013-11-07'),
INTERVAL 4 DAY)
group by admin
order by WEEK3) as q3)
where ADMIN1=ADMIN3 and ADMIN2=ADMIN3
group by admin1
order by WEEK1 desc
limit 25;
5.
select dt,sum(msu)
from wgr_raw
where dt >= date_sub(date('2013-11-01'),
INTERVAL 11 DAY)
group by dt
limit 7;
You can merge n number of select queries using UNION but there is one condition in UNION. Your all select fields should be same and order by will be common.
(
(SELECT a, b FROM tbl WHERE id >= 50 and id <= 100)
UNION
(SELECT a, b FROM tbl WHERE id >= 150 and id <= 200)
UNION
(SELECT a, b FROM tbl WHERE id >= 250 and id <= 300)
UNION
(SELECT a, b FROM tbl WHERE id >= 350 and id <= 400)
)
ORDER BY a