Suppose I have 5 records for a sales table.
ID Name datetime_col
1 ABC 2016-09-15 02:07:56
2 HSJ 2016-09-31 11:45:45
3 JSD 2016-11-26 07:09:56
4 JUH 2016-12-31 12:00:00
5 IGY 2017-01-13 14:00:07
I want to find how many records are there in sales table for each hour between 2016-09-15 AND 2017-01-13
Then result should be like
Hour sales_at_this_hour
2016-09-15 01:00:00 0
2016-09-15 02:00:00 1
2016-09-15 03:00:00 0
...
...
2017-01-13 01:00:00 0
2017-01-13 02:00:00 0
2017-01-13 03:00:00 0
....
2017-01-13 14:00:00 1
Then find the average of sales_at_this_hour using MySQL
EDIT: sorry not fully understand the question at first.
Use DATE_FORMAT
select
DATE_FORMAT(datetime_col, '%Y-%m-%d %h:00:00') as date,
count(id) as count
from table_name
group by date;
Get result with hours that has sales_at_this_hour > 1 (not exactly what you ask for)
datetime_col count
2016-02-04 05:00:00 5
2016-02-04 07:00:00 1
2016-02-04 08:00:00 5
2016-02-04 10:00:00 10
2016-02-04 11:00:00 1
Provide start_date and end_date, and then use DATEDIFF to calculate total time interval for the average calculation.
set #start_date = '2016-01-01', #end_date = '2017-01-01';
select
DATE_FORMAT(group_by_date.datetime, '%h:00:00') as hour,
AVG(group_by_date.count) / DATEDIFF(#end_date, #start_date) as average
from (
select
DATE_FORMAT(created_dtm, '%Y-%m-%d %h:00:00') as datetime,
count(id) as count
from table_name
where created_dtm > #start_date
and created_dtm < #end_date
group by datetime
) group_by_date
group by hour;
For each hour,
average sale count per day = total sale count / total days
hour average
01:00:00 0.03841209
02:00:00 0.01653005
03:00:00 0.0306716
04:00:00 0.01147541
05:00:00 0.01179831
Related
Data sample:
dtime
id
2021-01-01 06:00:00
1
2021-01-01 06:00:00
2
2021-01-01 06:00:00
3
...
...
2021-01-01 12:00:00
1
2021-01-01 12:00:00
2
2021-01-01 12:00:00
3
...
...
...
...
2021-01-12 20:00:00
1
2021-01-12 20:00:00
2
2021-01-12 20:00:00
3
In the real dataset, ids are between 1 and 9999, dtime are every 5 minutes, 24h/day, and I'd like to sample only at certain times (eg 06, 12, 16, 20h).
The expected output is the average of count(id) values, grouped by DATE(dtime), but:
Only certain TIME(dtime) should be sampled (eg 06, 12, 16, 20h);
count(id) should ignore id that are not between 10 and 500;
count(id) should be discarded (and not considered for the average) if <3.
Output sample:
DATE(dtime)
AVG(count(id))
2021-01-01
31
2021-01-02
29
So far I've got:
SELECT dtime,count(id)
FROM cron5min
WHERE (TIME(dtime) = '06:00:00' OR TIME(dtime) = '12:00:00' OR TIME(dtime) = '16:00:00' OR TIME(dtime) = '20:00:00') AND id BETWEEN 10 AND 500 AND estado = 1
GROUP BY dtime
and then I'm using PHP to do the average and discard data according to 3.
I'm now trying to do this with a MySQL statement only, no PHP.
You need 2 levels of aggregation:
SELECT DATE(dtime) date, AVG(counter) avg_count
FROM (
SELECT dtime, COUNT(id) counter
FROM cron5min
WHERE TIME(dtime) IN ('06:00:00', '12:00:00', '16:00:00', '20:00:00')
AND id BETWEEN 10 AND 500
AND estado = 1
GROUP BY dtime
HAVING counter >= 3
) t
GROUP BY date
MySQL version 8.0
I want to calculate time difference between two datetime column.
And get rows where duration >= 12:00:00.
which I would normally do:
select id
, start_time
, end_time
, timediff(end_time, start_time) as duration
from table;
which I would get something like this:
id start_time end_time duration
0 1 2020-06-01 01:00:00 2020-06-01 14:00:00 13:00:00
1 2 2020-06-01 01:00:00 2020-06-01 18:00:00 17:00:00
2 3 2020-06-01 19:00:00 2020-06-02 10:00:00 15:00:00
3 4 2020-06-02 04:00:00 2020-06-02 16:00:00 12:00:00
For duration column I don't want times between 00:00:00 ~ 04:00:00 to be added towards the duration. So for the first row duration = 10:00:00 since 01:00:00~14:00:00 = 10:00:00, ignoring times between 00:00:00 ~ 04:00:00
same for second row we substract 3 hours from duration.
so my desired output would be:
id start_time end_time duration
0 1 2020-06-01 01:00:00 2020-06-01 14:00:00 10:00:00
1 2 2020-06-01 01:00:00 2020-06-01 18:00:00 14:00:00
2 3 2020-06-01 19:00:00 2020-06-02 10:00:00 11:00:00
3 4 2020-06-02 04:00:00 2020-06-02 16:00:00 12:00:00
There are lots of rows where times include minutes and seconds too.
Thanks in advance!
I've grabbed all rows where duration >= 12:00:00.
Then separated data into 4 regions depending on their start_time.
a_region = 00~04
b_region = 04~12
c_region = 12~16
d_region = 16~24
For a_region I've subtracted 04:00:00 - start_time which is time we should compensate to duration in a_region.
compensation = 04:00:00 - start_time
compensated_time = duration - compensation.
For b_region it needs no compensation if it has passed 00~04 it means it already passed duration = 12:00:00.
For c_region,
compensation = 16:00:00 - start_time
compensated_time = duration - compensation
For d_region since we've grabbed duration >= 12:00:00
it will pass all of 00~04 therefore
compensated_time = duration - 04:00:00.
I solved it using Python but above is the logic I've used.
One option uses greatest():
select id
, start_time
, end_time
, timediff(
greatest(,
end_time,
date_format(end_time, '%Y-%m-%d 04:00:00')
),
greatest(
start_time,
date_format(start_time, '%Y-%m-%d 04:00:00')
)
) as duration
from table;
My table have fields that represent starting and ending working period as datetime.
I need to find related entries that match a total of 14hours min over a sliding period of 24 hours.
I think window function will (maybe) save me, but MariadDB (i use) doesn't implement yet Range time intervals in window function.
here is some example data:
id starting_hour ending_hour
-- ------------------- -------------------
1 2018-09-02 06:00:00 2018-09-02 08:30:00
2 2018-09-03 08:30:00 2018-09-03 10:00:00
4 2018-09-03 11:00:00 2018-09-03 15:00:00
5 2018-09-02 15:30:00 2018-09-02 16:00:00
6 2018-09-02 16:15:00 2018-09-02 17:00:00
7 2018-09-20 00:00:00 2018-09-20 08:00:00
8 2018-09-19 10:00:00 2018-09-19 12:00:00
9 2018-09-19 12:00:00 2018-09-19 16:00:00
10 2018-10-08 12:00:00 2018-10-08 14:00:00
11 2018-10-29 09:00:00 2018-10-29 10:00:00
So how to find rows where in a 24 hours window their sum a more or equal to 14 hours.
thanks
Edit:
SELECT
id,
starting_hour,
ending_hour,
TIMEDIFF (ending_hour, starting_hour) AS duree,
(
SELECT SUM(TIMEDIFF(LEAST(ending_hour, DATE_ADD(a.starting_hour, INTERVAL 24 HOUR)), starting_hour)) / 10000
FROM `table` b
WHERE b.starting_hour BETWEEN a.starting_hour AND DATE_ADD(a.starting_hour, INTERVAL 24 HOUR)
) AS duration
FROM
`table` a
HAVING duration >= 14
ORDER BY starting_hour ASC
;
This returns Id 8 but i want the whole period. (eg: Id 8, Id 9 and Id 7)
EDIT2:
The expected results are ranges of working time where they are in a window of 24 hours and where their sum are more or equal to 14 hours.
EDIT 3:
In fact under MySQL 8 this seems to work.
SELECT * FROM (
SELECT
*,
SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(hs.`ending_hour`, hs.`starting_hour`))) OVER (ORDER BY hs.starting_hour RANGE BETWEEN INTERVAL '12' HOUR PRECEDING AND INTERVAL '12' HOUR following)) AS tot
FROM
table hs
WHERE hs.`starting_hour` > DATE_SUB(NOW(), INTERVAL 50 DAY) AND hs.`ending_hour` <= NOW()
ORDER BY hs.`starting_hour` ASC
) t1
HAVING tot >= '14:00:00'
;
Is there a way to do it under MariaDB 10.2 without window function ? Or without window range function ?
I have these rows
id | start_time |
1 | 2018-06-15 02:00:00 |
2 | 2018-06-15 02:45:00 |
3 | 2018-06-15 03:45:00 |
I want to select rows that are 1 hour before the start_time. So if the time is 2018-06-15 01:00:00 then the first row should be returned.
How do i do this? I've tried below but i don't know how to subtract 1 hour from start_time.
SELECT *
FROM table1
WHERE DATE_FORMAT(start_time, '%Y-%m-%d %H') <= DATE_FORMAT(NOW(), '%Y-%m-%d %H');
To subtract hours ,use date_sub function
In your case
SELECT DATE_SUB(DATE_FORMAT(start_time, '%Y-%m-%d %H'), INTERVAL 1 HOUR)
i have a mysql customers table:
customer_id | customer_name | creation_date
1 | john | 2013-09-12 18:34:00
2 | banjo | 2013-01-11 14:34:00
what i would to achieve is to know the closest DAY in the current ot next month that match the creation_date field.
I.E if the current date is 2014-01-20, i would like to have the following result
customer_id | customer_name | creation_date | next_date
1 | john | 2013-09-12 18:34:00 | 2014-02-12
2 | banjo | 2013-01-11 14:34:00 | 2014-02-11
The following seems to work but not tested for edge cases:
SELECT
CURRENT_DATE AS cutoff_date,
date_column AS creation_date,
CASE
WHEN STR_TO_DATE(CONCAT_WS('-', YEAR(CURRENT_DATE), MONTH(CURRENT_DATE), DAY(date_column)), '%Y-%c-%e') >= CURRENT_DATE
THEN STR_TO_DATE(CONCAT_WS('-', YEAR(CURRENT_DATE), MONTH(CURRENT_DATE), DAY(date_column)), '%Y-%c-%e')
ELSE STR_TO_DATE(CONCAT_WS('-', YEAR(CURRENT_DATE), MONTH(CURRENT_DATE), DAY(date_column)), '%Y-%c-%e') + INTERVAL 1 MONTH
END AS next_date
FROM dates2
Results:
cutoff_date creation_date next_date
------------------- ------------------- -------------------
2014-01-20 00:00:00 2010-01-01 00:41:00 2014-02-01 00:00:00
2014-01-20 00:00:00 2010-01-10 00:06:00 2014-02-10 00:00:00
2014-01-20 00:00:00 2010-01-19 22:34:00 2014-02-19 00:00:00
2014-01-20 00:00:00 2010-01-19 23:13:00 2014-02-19 00:00:00
2014-01-20 00:00:00 2010-01-20 00:36:00 2014-01-20 00:00:00
2014-01-20 00:00:00 2010-01-20 00:43:00 2014-01-20 00:00:00
2014-01-20 00:00:00 2010-02-15 08:05:00 2014-02-15 00:00:00
2014-01-20 00:00:00 2010-02-25 22:50:00 2014-01-25 00:00:00
First calculate the wanted date, than use min/max to get the closest one. Maybe something like that:
-- If your stored date is always in year 2013
select CASE WHEN DATE_ADD(DATE_ADD(creation_date, INTERVAL 1 YEAR), INTERVAL 1 MONTH) < SYSDATE
THEN DATE_ADD(creation_date, INTERVAL 1 YEAR)
ELSE DATE_ADD(DATE_ADD(creation_date, INTERVAL 1 YEAR), INTERVAL 1 MONTH)
END AS next_date
from customers;
This will make your creation_date 2013-09-12 to 2014-10-12. But if you just want the day maybe this is useful?:
-- If your stored date is always in year 2013
select str_to_date(concat(date_format(curdate(),'%Y-%m'), date_format(creation_date,'%d')),'%Y-%m-%d') as next_date
from customers;
This should use the current year and month, but change just the day. You can use a CASE to check if the difference between the current or the next month is closer.
You can try this, in mysql you can use interval for perticuler increament date like:
select customer_id,customer_name,creation_date,(creation_date+interval 1 year) as next_date from customer_info;
if you want,
next year then use- (creation_date + interval 1 year)
next month then use- (creation_date + interval 1 month)
for perticular day use- (creation_date + interval 5 day)