MySQL SELECT query with timetable - mysql

I have trouble creating Mysql query that will give me a list of id depending on the current time and timetable specified. I have a table like so:
ID - int
0f - time (monday from)
0t - time (monday till)
1f - time (tuesday from)
1t - time (tuesday till)
2f - time (wednesday from)
2t - time (wednesday till)
3f - time (thursday from)
3t - time (thursday till)
4f - time (friday from)
4t - time (friday till)
5f - time (saturday from)
5t - time (saturday till)
6f - time (sunday from)
6t - time (sunday till)
The problem starts when "till" value is grater than 24 hour and becomes lower then "from" value.
For example, it is 1am and I need to select all ids that work now and one works from 10am till 2am.
UPD That is an example of my table with real data:
ID Name f0 t0 f1 t1 f2 t2 f3 t3 f4 t4 f5 t5 f6 t6
23 test1 10:00:00 23:00:00 10:00:00 23:00:00 10:00:00 23:00:00 10:00:00 23:00:00 10:00:00 01:00:00 11:00:00 01:00:00 11:00:00 23:00:00
24 test2 12:00:00 01:00:00 12:00:00 01:00:00 12:00:00 01:00:00 12:00:00 01:00:00 12:00:00 02:00:00 12:00:00 02:00:00 12:00:00 01:00:00
25 test3 12:00:00 01:00:00 12:00:00 01:00:00 12:00:00 01:00:00 12:00:00 01:00:00 12:00:00 02:00:00 12:00:00 02:00:00 12:00:00 01:00:00
27 test4 11:00:00 23:00:00 11:00:00 23:00:00 11:00:00 23:00:00 11:00:00 23:00:00 11:00:00 23:00:00 11:00:00 23:00:00 11:00:00 23:00:00
28 test5 10:00:00 23:00:00 10:00:00 23:00:00 10:00:00 23:00:00 10:00:00 23:00:00 10:00:00 23:00:00 10:00:00 23:00:00 10:00:00 23:00:00
29 test6 09:00:00 22:00:00 09:00:00 22:00:00 09:00:00 22:00:00 09:00:00 22:00:00 09:00:00 22:00:00 10:00:00 23:00:00 10:00:00 23:00:00
30 test7 12:00:00 01:00:00 12:00:00 01:00:00 12:00:00 01:00:00 12:00:00 01:00:00 12:00:00 03:00:00 12:00:00 03:00:00 12:00:00 01:00:00
32 test8 09:00:00 22:00:00 09:00:00 22:00:00 09:00:00 22:00:00 09:00:00 22:00:00 09:00:00 22:00:00 10:00:00 22:00:00 10:00:00 22:00:00
33 test9 11:00:00 22:00:00 11:00:00 22:00:00 11:00:00 22:00:00 11:00:00 22:00:00 11:00:00 22:00:00 11:00:00 22:00:00 11:00:00 22:00:00
34 test10 09:00:00 22:00:00 09:00:00 22:00:00 09:00:00 22:00:00 09:00:00 22:00:00 09:00:00 22:00:00 09:00:00 22:00:00 09:00:00 22:00:00
35 test11 18:00:00 02:00:00 18:00:00 02:00:00 18:00:00 02:00:00 18:00:00 02:00:00 18:00:00 04:00:00 18:00:00 04:00:00 18:00:00 02:00:00
AND I need to write MYSQL query to select ID's that are open now at any time

I'm not completely sure what you're asking for here. So I will offer a couple of observations.
First, given any DATE, TIMESTAMP, or DATETIME value, for example a column with the name datestamp, this formula will give you precisely midnight of the Monday of that week. (There's a little bit of magic in this formula, because MySQL's DAY 0 happens to be a Sunday.)
FROM_DAYS(TO_DAYS(datestamp) -MOD(TO_DAYS(datestamp) -2, 7))
Then, you can add an arbitrary number of hours to that. So, for example, if you have an eight-hour work shift that begins at 23:00 on Wednesday, it begins 71 (24 + 24 + 23) hours after the beginning of the present week. So it begins at
FROM_DAYS(TO_DAYS(NOW()) -MOD(TO_DAYS(NOW()) -2, 7))
+ INTERVAL 71 HOUR
The end of that shift in the present week, eight hours later, is at this time.
FROM_DAYS(TO_DAYS(NOW()) -MOD(TO_DAYS(NOW()) -2, 7))
+ INTERVAL 71 HOUR
+ INTERVAL 8 HOUR
So, maybe (???) you want to represent your "Thursday till" sorts of items as hours after the beginning of the week.
This is just an idea for a way to represent recurring weekly events in your dbms, while still getting the advantages of MySQL's date arithmetic.

Related

Mysql datetime count the hours worked between a specific time

I'm looking for a way to count the hours worked between a given time range.
For example to count from the MySQL data below the hours worked between 22:00 and 06:00.
Using date_start 2022-04-01 21:00:00 and date_end 2022-04-02 08:00:00 the user worked 11 hours total and 8 night hours.
Of course the data could also be something like 2022-04-01 05:00:00 and 2022-04-01 16:00:00 which will then need to output 2 night hours or 2022-04-01 18:00:00and 2022-04-02 03:00:00 which outputs 5 night hours.
MySQL table:
CREATE TABLE `tasks` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date_start` datetime DEFAULT NULL,
`date_end` datetime DEFAULT NULL,
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `tasks` (`date_start`,`date_end`) VALUES
('2022-04-01 04:00:00', '2022-04-01 16:00:00'), # 2:00 nighthours
('2022-04-02 05:00:00', '2022-04-02 23:30:00'), # 2:30 nighthours
('2022-04-03 06:00:00', '2022-04-03 18:00:00'), # 0:00 nighthours
('2022-04-04 12:00:00', '2022-04-05 00:00:00'), # 2:00 nighthours
('2022-04-05 19:00:00', '2022-04-06 07:00:00'); # 8:00 nighthours
Current MySQL:
# 21600 = 06:00 hours
# 79200 = 22:00 hours
SELECT t.date_start, t.date_end, DATE_FORMAT(TIMEDIFF(
(CASE WHEN DATE(t.date_start) != DATE(t.date_end) AND TIME_TO_SEC(t.date_end) > 21600 THEN DATE_FORMAT(t.date_end, '%Y-%m-%d 06:%i:%s')
WHEN TIME_TO_SEC(t.date_start) < 21600 THEN DATE_FORMAT(t.date_start, '%Y-%m-%d 06:%i:%s')
ELSE t.date_end END),
(CASE WHEN DATE(t.date_start) != DATE(t.date_end) AND TIME_TO_SEC(t.date_start) < 79200 THEN DATE_FORMAT(t.date_start, '%Y-%m-%d 22:%i:%s')
WHEN TIME_TO_SEC(t.date_end) > 79200 THEN DATE_FORMAT(t.date_start, '%Y-%m-%d 22:%i:%s')
WHEN DATE(t.date_start) = DATE(t.date_end) AND TIME_TO_SEC(t.date_end) <= 79200 AND TIME_TO_SEC(t.date_start) >= 21600 THEN t.date_end
ELSE t.date_start END)
), '%H:%i') AS night_time FROM tasks t;
Currently I still have a problem in my current MySQL when the start_date and end_date both start on the same day and both have night hours. for example 2022-04-02 05:00:00 and 2022-04-02 23:30:00 which has 01:00 night hour in start_date and 1:30 hour in end_date (total night: 02:30 hours)
I am not sure if my current MySQL is the best/fastest way to achieve my goal.
Calculating Time Overlaps
You can calculate the amount of time two date ranges overlap using:
MIN( EndDate1, EndDate2 ) - MAX( StartDate1, StartDate2 )
For example if the date ranges are:
Date_Start
Date_End
Night_Shift_Start
Night_Shift_End
2022-04-01 21:00:00
2022-04-02 08:00:00
2022-04-01 22:00:00 **
2022-04-02 06:00:00 **
The result would be 8 hours:
Min( EndDate ) - Max( StartDate )
.... As Unix Timestamps
Time Overlap
2022-04-02 06:00:00 (minus) 2022-04-01 22:00:00
1648875600 - 1648846800 = 28800 seconds
08:00:00 hours
Checking for Multiple Overlaps
Since technically a single shift could have both started and ended during "night hours" (22:00 to 06:00) you need check for overlaps on both sides.
Date_Start
Date_End
Night Hours
...
2022-04-05 05:00:00
2022-04-05 23:30:00
2.5 hours
(1 hour) : 2022-04-05 05:00 to 2022-04-05 06:00 (1.5 hours) : 2022-04-05 22:00 to 2022-04-05 23:30
One approach is using the base start/end times to calculate the previous and upcoming "night hour" periods:
SELECT *
, TIMESTAMP(DATE(date_start) - INTERVAL 1 DAY, '22:00:00') AS current_start
, TIMESTAMP(DATE(date_start), '06:00:00') AS current_end
, TIMESTAMP(DATE(date_start), '22:00:00') AS next_start
, TIMESTAMP(DATE(date_start) + INTERVAL 1 DAY, '06:00:00') AS next_end
FROM tasks
Results:
id
date_start
date_end
current_start
current_end
next_start
next_end
1
2022-04-01 04:00:00
2022-04-01 16:00:00
2022-03-31 22:00:00
2022-04-01 06:00:00
2022-04-01 22:00:00
2022-04-02 06:00:00
2
2022-04-02 05:00:00
2022-04-02 23:30:00
2022-04-01 22:00:00
2022-04-02 06:00:00
2022-04-02 22:00:00
2022-04-03 06:00:00
3
2022-04-03 06:00:00
2022-04-03 18:00:00
2022-04-02 22:00:00
2022-04-03 06:00:00
2022-04-03 22:00:00
2022-04-04 06:00:00
4
2022-04-04 12:00:00
2022-04-05 00:00:00
2022-04-03 22:00:00
2022-04-04 06:00:00
2022-04-04 22:00:00
2022-04-05 06:00:00
5
2022-04-05 19:00:00
2022-04-06 07:00:00
2022-04-04 22:00:00
2022-04-05 06:00:00
2022-04-05 22:00:00
2022-04-06 06:00:00
6
2022-04-01 04:00:00
2022-04-01 16:00:00
2022-03-31 22:00:00
2022-04-01 06:00:00
2022-04-01 22:00:00
2022-04-02 06:00:00
7
2022-04-05 19:00:00
2022-04-06 07:00:00
2022-04-04 22:00:00
2022-04-05 06:00:00
2022-04-05 22:00:00
2022-04-06 06:00:00
8
2022-04-05 05:00:00
2022-04-05 23:30:00
2022-04-04 22:00:00
2022-04-05 06:00:00
2022-04-05 22:00:00
2022-04-06 06:00:00
Total Overlap Time
Once you have the "night hour" ranges, calculate the overlapping time on both sides and add them together to get the total time worked during "night hours"
SELECT id
, date_start
, date_end
, SEC_TO_TIME(
GREATEST(0, start_overlap__in_seconds) -- ignore negative time, which means no overlap
+ GREATEST(0, end_overlap_in_seconds)
) AS time_overall
FROM (
SELECT *
, UNIX_TIMESTAMP(LEAST(date_end, current_end))
- UNIX_TIMESTAMP(GREATEST(date_start, current_start))
AS start_overlap__in_seconds
, UNIX_TIMESTAMP(LEAST(date_end,next_end))
- UNIX_TIMESTAMP(GREATEST(date_start,next_start))
AS end_overlap_in_seconds
FROM (
SELECT *
, TIMESTAMP(DATE(date_start) - INTERVAL 1 DAY, '22:00:00') AS current_start
, TIMESTAMP(DATE(date_start), '06:00:00') AS current_end
, TIMESTAMP(DATE(date_start), '22:00:00') AS next_start
, TIMESTAMP(DATE(date_start) + INTERVAL 1 DAY, '06:00:00') AS next_end
FROM tasks
) tmp
) t
Final Results:
id
date_start
date_end
time_overall
1
2022-04-01 04:00:00
2022-04-01 16:00:00
02:00:00
2
2022-04-02 05:00:00
2022-04-02 23:30:00
02:30:00
3
2022-04-03 06:00:00
2022-04-03 18:00:00
00:00:00
4
2022-04-04 12:00:00
2022-04-05 00:00:00
02:00:00
5
2022-04-05 19:00:00
2022-04-06 07:00:00
08:00:00
6
2022-04-01 04:00:00
2022-04-01 16:00:00
02:00:00
7
2022-04-05 19:00:00
2022-04-06 07:00:00
08:00:00
8
2022-04-05 05:00:00
2022-04-05 23:30:00
02:30:00
db<>fiddle here

Time difference without considering times between 0am ~ 4am. MySQL

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;

Get 30 minutes interval data between start and end time in mysql

I have table structure in mysql,
table_id no_people booking_date bookingend_time bookingstart_time
14 2 2014-10-31 2014-10-31 13:30:00 2014-10-31 11:00:00
5 4 2014-10-31 2014-10-31 16:30:00 2014-10-31 14:30:00
6 2 2014-10-31 2014-10-31 17:00:00 2014-10-31 16:00:00
2 4 2014-11-06 2014-11-06 12:30:00 2014-11-06 10:00:00
2 4 2014-10-31 2014-10-31 16:00:00 2014-10-31 14:00:00
3 4 2014-11-01 2014-11-01 09:00:00 2014-11-01 07:30:00
6 2 2014-11-01 2014-11-01 10:00:00 2014-11-01 07:30:00
2 4 2014-11-03 2014-11-03 10:30:00 2014-11-03 08:30:00
5 4 2014-11-04 2014-11-04 10:30:00 2014-11-04 08:30:00
3 4 2014-11-05 2014-11-05 09:30:00 2014-11-05 07:30:00
14 2 2014-11-05 2014-11-05 09:30:00 2014-11-05 07:30:00
I want to retrieve table_id data with 30 minutes of interval between start and end time.
Ex:
if i give booking start time 10:30 and end time 12:30 i should get 14 as row..
Similarly it should check all rows and return between two times ..
My query so far
SELECT `table_id` FROM `booking` WHERE bookingstart_time>='2014-10-31 10:30:00' AND bookingend_time<='2014-10-31 11:30:00'
Step 1: expand the input time frame by 30 minutes before and 30 minutes after. DATE_ADD() and DATE_SUB() can do that:
DATE_SUB(_input_start_date_here_, INTERVAL 30 MINUTE)
Step 2: rethink your problem in terms of start and end times. Here are the possible cases:
if the booking started during the (expanded) period, then you want this booking in your result
or if the booking started before the period, then you want this booking unless it also ended before the period
on the other hand, if the booking started after the period, then you do not want this booking
The first situation above could be expressed like this:
WHERE bookingstart_time >= DATE_SUB(_input_start_date_here_, INTERVAL 30 MINUTE)
AND bookingstart_time <= DATE_ADD(_input_end_date_here_, INTERVAL 30 MINUTE)
The second condition is left as an exercise. You can also rewrite the above with a more elegant BETWEEN operator.
SELECT restaurant_table FROM rest_restaurantbooking WHERE TIMESTAMPDIFF(SECOND, bookingstart_time, bookingend_time) > 1800.
FOR REFERENCE: HERE

Overriding Data based on sub query

I have a Rates table that records the rate of a process
DateTime Rate
2013-11-25 05:00:00 22
2013-11-25 06:00:00 78
2013-11-25 07:00:00 33
2013-11-25 07:10:00 56
2013-11-25 08:30:00 12
and a Downtime table that records time periods where the above data may not be valid
StartDateTime EndDateTime
2013-11-25 04:59:00 2013-11-25 05:10:00
2013-11-25 07:00:00 2013-11-25 07:15:00
How can I get the following output where any Rate value recorded between any period in the Downtime table is replaced by a fixed value e.g. 50?
DateTime Rate
2013-11-25 05:00:00 50
2013-11-25 06:00:00 78
2013-11-25 07:00:00 50
2013-11-25 07:10:00 50
2013-11-25 08:30:00 12
This should do the trick:
SELECT r.datetime, if(d.startDatetime IS NULL, r.rate, 50) rate
FROM rates r
LEFT JOIN downtime d
ON r.datetime BETWEEN d.startDatetime AND d.endDatetime
Fiddle here.

how to get latest datetime from multiple same dates in mysql

how do i get the latest datetime from multiple same dates in mysql?
SELECT start_time FROM times WHERE start_time BETWEEN '2013-01-27' AND '2013-02-02' ORDER BY start_time
this outputs:
2013-01-27 00:00:00
2013-01-28 09:00:00
2013-01-29 00:00:00
2013-01-30 09:00:00
2013-01-31 00:00:00
2013-02-01 09:00:00
2013-02-01 21:00:00
2013-02-02 00:00:00
i want all this to output except i want the latest datetime for 2013-02-01
so it would output like this:
2013-01-27 00:00:00
2013-01-28 09:00:00
2013-01-29 00:00:00
2013-01-30 09:00:00
2013-01-31 00:00:00
2013-02-01 21:00:00 <<<<<<<<
2013-02-02 00:00:00
SELECT MAX(start_time)
FROM times
WHERE start_time BETWEEN '2013-01-27 00:00:00' AND '2013-02-02 23:59:59'
GROUP BY DATE(start_time)
ORDER BY start_time
SQLFiddle Demo