Finding free timeslots between appointments with preferred beginning - mysql

I have 2 tables...
appointments:
id (int)
start (datetime)
end (datetime)
timeslots:
id (int)
timeslot (time)
The table timeslots has records like this...
00:00:00
00:05:00
00:10:00
...
23:55:00
The table appointments has one record...
start: 2017-05-15 01:30:00
end: 2017-05-15 02:00:00
With the following simplified query I try to get the first free starting timeslot each hour if there is no prefered hourly begin time while respecting existing appointments...
SET #mandatory=true, #parallel=1, #targetdate="2017-05-15", #begin='30', #duration='00:30:00', #time_start="00:00:00", #time_end="03:00:00";
SELECT MIN(timeslot) AS free_slot FROM timeslots
INNER JOIN
appointments
ON 1=1
WHERE timeslots.timeslot BETWEEN #time_start AND #time_end
AND (ADDTIME(timeslot, #duration) BETWEEN #time_start AND #time_end)
AND ((#mandatory AND MINUTE(timeslot)=#begin) OR (NOT #mandatory))
AND ((
SELECT COUNT(*) AS anzahl
FROM appointments
WHERE (concat(date(#targetdate)," ",timeslots.timeslot) BETWEEN appointments.start AND appointments.end - INTERVAL 1 SECOND
OR concat(date(#targetdate)," ", ADDTIME(timeslot, #duration) ) BETWEEN appointments.start AND appointments.end - INTERVAL 1 SECOND)
) < #parallel)
GROUP BY HOUR(timeslot)
Explanation of parameters:
#mandatory:
TRUE means, I only allow timeslots matching #begin. FALSE means, I prefer(!) timeslots matching #begin, but if there is no match, I would like to get the first free timeslot each hour.
#parallel:
Number of parallel appointments allowed. The value 1 means, that there should be no overlapping appointments. The value 2 means, that there should be only 2 appointments at the same time.
#targetdate:
The query should return timeslots only for the targetdate.
#begin:
The prefered beginning of the free timeslots. '30' means, that I would like to get timeslots starting "half past ..." every hour.
#duration: The needed duration of consecutive free timeslots.
#time_start and #time_end:
The result should only contain records within this time range.
My problem is, that I get either free timeslots only starting at half past ... or the first free timeslot for every full hour - depending on setting #mandatory to TRUE or FALSE.
When setting #mandatory to TRUE I think I get the desired result (only timeslots starting at the defined begin time). But I want to set #mandatory to FALSE and get first free timeslot every hour ONLY when there is no free timeslot beginning with half past (I would like to PREFER the matching begin timeslots, but offer alternative timeslots...
This is what I would like to get:
00:30:00
01:00:00 (this row respects the existing appointment at half past one and returns the first free timeslot for this hour only when the duration of the remaining timeslots fits)
02:30:00
Is there an easy way to get these results?
Best regards

Related

Find next available time slot in "calendar"

I have the following MySQL tables:
ServiceProviders- id, ...other irrelevant columns
ProvidersWorkHours - id, providerId, day(enum[1,2,3,4,5,6,7]), startTime(time), endTime(time)
Service- id, duration, ...other irrelevant columns
Groups- id, serviceId, providerId,size, duration
GroupReservations- groupId, customerId.
ServiceProviders have their own workHours (when they're available to work), they can create Groups of different sizes and of different durations (they can be longer or shorter than regular service duration). I need to find next available time slot for regular service duration that is not reserved or a group still not completely filled (for example group of size 2 that has only 1 reservation is a valid one).
Expected outcomes:
Current date: 2022-06-20 18:24 (MONDAY)
Regular service duration: 45 minutes
Provider workHours: [MONDAY 08:00-17:00, TUESDAY 08:00-17:00, WEDNESDAY 08:00-17:00]
Some expected scenarios:
We have new provider, with no groups, no reservations. Expected nextAvailableSlot 2022-06-21 08:00
We have only one full group at 2022-06-27 12:00. Next availableSlot still should be 2022-06-21 08:00
We have group of size 2 that has only 1 reservation at 2022-06-21 08:00. Next available slot should be 2022-06-21 08:00
We have full groups till 2022-06-21 16:00 (last one ends at 16:00). Next availableSlot should be 2022-06-21 16:00.
As I was thinking we can't go through solution that I found in other places (join same reservations table with itself, in my case it would be groups). It's bad since I can have no groups, or my first group a week ahead of currentDate. Probably what would work is to take currentTime and keep adding regular serviceTime and check all the constrains, until it does not intersect with any reservations, or until it find a group that isn't filled yet. Not sure how to do it in MySQL, though. Any ideas or other solutions?

Get value difference between two dates in MySQL

I have a following table structure:
page_id view_count date
1 30 2018-08-30
1 33 2018-08-31
1 1 2018-09-01
1 5 2018-09-02
...
View count is reset on 1st of every month, and it's current value is stored on a daily basis, so on 31st of August it was increased by 3 (because 33-30).
What I need to do is to retrieve the view count (difference) between two dates through SQL query. To retrieve view count between two dates in same month would be simple, by just subtracting bigger date with the lower date, but retrieving between two dates that are in different months is what's not sure to me how to achieve. If I wanted to retrieve data between 2018-08-13 and 2018-09-13 I would have to get difference between 2018-08-31 and 2018-08-13, and add it to the value of 2018-09-13.
Also, I would like to do it for all page_id at once, between the same dates if possible within a single query.
assuming that the counter is unique per page and that the page_id counter is inserted daily into the table, I think that such a solution would work
The dates are based on the example,
and should be replaced by the relevant parameters
SELECT
v1.view_count + eom.view_count - v2.view_count
FROM
view_counts v1
INNER JOIN view_counts v2 ON v2.page_id = v1.page_id AND v2.`date` = '2018-08-13'
INNER JOIN view_counts eom ON v2.page_id = v.page_id AND eom.`date` = LAST_DAY(DATE_ADD(v.`date`, INTERVAL -1 MONTH))
WHERE
`date` = '2018-09-13'

MySQL - Chaining multiple SQL commands

I've looked upon multiple threads but can't seem to find a desirable answer to my question. I am creating a system with a scheduler in it and I need multiple chains in order for the query to return an answer. So here is the scenario. A user needs to register and upon registration, the user is presented with a date.
I have users table where users(obviously) are listed. One column here has the date.
There is also a date table where the dates are stored. Each date can only occupy 30 persons.
The date table also has the availability column. If the date is available, it is labeled 1. If the date has expired (the current date is higher than this date), it is labeled 0.
for example, i have dates Jan 1, Jan 2 and Jan 3 and the current date is Jan 2. Obviously, Jan 1 should be expired. That wouldn't be included in the list so I will set the availability to 0 (yes, manually). There is only Jan 2 and Jan 3. I also need to find if Jan 2 has accommodated 30 people. Else, I need to put him to Jan 3. I got a bunch of parts of the codes that I don't know how to chain.
Expected Output :
query1 (Jan 2 and Jan 3 should be the result)
SELECT * FROM rooms WHERE availability = 0
RoomID Room Date Room Availability
1 Jan 1 1
2 Jan 2 0
3 Jan 3 0
query2 - (count people assigned in specific rooms)
SELECT COUNT(RoomAssigned) FROM users
Users RoomAssigned
Jack 2
Eddie 2
query3 - (system should be able to locate the first room that is available)
if (query2 results<30)
put new user to rooms from result in query1
If ever the chaining I was looking for would possibly be not advisable, I am open for different suggestions. Thanks. :)
Your question seems to be very confused about what tables you have and what's in them, and I don't see how your sample queries can produce the output you showed. But it seems like this query will do what you want:
SELECT *
FROM rooms
WHERE availability = 1
AND roomID NOT IN (
SELECT roomAssigned
FROM users
WHERE availability = 1
GROUP BY roomAssigned
HAVING COUNT(*) >= 30)
ORDER BY roomDate
LIMIT 1
The subquery finds all the rooms that are filled, and then we exclude those from the main query. Then we sort the remaining rooms by date, and select the first one with LIMIT 1.
I think you're going to want something like this:
SELECT r.[RoomID],
r.[Room Date]
FROM rooms r
LEFT JOIN users u
ON r.[RoomID] = u.[RoomAssigned]
WHERE r.[Room Date] >= CURDATE()
GROUP BY r.[RoomId], r.[Room Date]
ORDER BY r.[Room Date], r.[Room Id]
HAVING COUNT(u.[RoomAssigned]) < 30
LIMIT 1
I haven't tested it, so it may require some tweaking. It's like #Barmar's answer, only using a join instead of a nested select. I also checked the availability based on the current date, not the availability column, which I don't think should be stored in the database, because it can be determined based on the Room Date.

Finding available timeslots in a day based on existing records in MySQL

I have a table that has these fields:
How would I find all available time slots for that day (based on the day starting at 7am and ending at 10pm) that aren't currently in this table? For example, on one particular day, if all timeslots from 7am till 10pm were taken bar one at 6pm till 7pm, that would be the one result.
The duration of each time slot does not vary - they all last one hour.
I have tried many different things, but I have a feeling I am so far off, it is hardly worth posting what I've tried.
Any help would be greatly appreciated!
One thing I would think about would be having a "hours table" with all the values you wanna check. Then, with a left join and selecting only null values, you'd get only the values you haven't assigned. I built a SQLfiddle http://sqlfiddle.com/#!2/66b441/6 to check it with some dummy values to show how this works:
SELECT h.slot
FROM hours h
LEFT JOIN deliveries d
ON ( h.slot = d.start_time AND date_stamp = '2014-04-04' )
WHERE start_time IS NULL
Check the data in the SQLfiddle, if you know the slots and they don't overlap, with that you will get for the date the values
SLOT
January, 01 1970 07:00:00+0000
January, 01 1970 10:00:00+0000

Time difference between dates, including business hour and excluding holidays

How can I calculate the time difference between two date, considering:
Only Monday to Friday
Time between 9am to 5:30pm;
Exclude Holidays.
Example:
d1 = 2012-10-05 17:00:00
d2 = 2012-14-09 12:00:00
Calculation Steps:
2012-10-05 = 00:30:00
2012-10-06 = 00:00:00
2012-10-07 = 00:00:00
2012-10-08 = 07:30:00
2012-10-09 = 04:00:00
ddiff(d2,d1) = 12:00:00
I know how to do it using only mon-fri, as described here. And I am talking about MySQL.
I've come up with a solution that's relatively straightforward for calculating the time difference for the full interim dates. However it's a bit messy to use mysql for calculating the time difference for the start & end dates. I have included them in my solution, but with a number of assumptions.
In any case, here's the sql
SET #startdate:='2012-12-24 17:00:00';
SET #enddate:='2013-01-02 12:00:00';
SELECT
TIME_TO_SEC(TIMEDIFF(CONCAT(DATE(#startdate),' 17:30:00'), #startdate))/3600 as startday_time,
TIME_TO_SEC(TIMEDIFF(#enddate, CONCAT(DATE(#enddate),' 9:00:00')))/3600 as endday_time,
SUM(daily_hours) as otherdays_time from
(
SELECT 7.5 as daily_hours, id, DATE_ADD(DATE(#startdate),INTERVAL id-1 DAY) as idate from numbers
) dates
LEFT JOIN holidays on DATE(dates.idate) = DATE(holidays.date)
WHERE
idate BETWEEN #startdate AND #enddate
AND holidays.date IS NULL
AND DAYOFWEEK(idate) <> 7 AND DAYOFWEEK(idate) <> 1;
sqlfiddle here:
http://sqlfiddle.com/#!2/ff3f3/1/2
To get the valid interim dates, we'll need two tables - a holidays table listing all the holiday dates and a numbers table that contains a series of integers which is very useful for joining against to get a sequential series of dates (with no gaps).
Note: In the sqlfiddle, I've populated the numbers table only up to 12 to cover the dates used in my example - it will probably need to be populated to a higher number depending on the range of dates you'll be working with.
For the start day time & end day time, I've made the following assumptions:
that start date & end date are both valid dates that should be counted towards the total time
that the time on the start date is between lunch and 17.30
that the time on the end date is between lunch and 17.30
if these assumptions are wrong, you're getting into serious conditional territory (with lots of ifs) and might be best doing this in the php (or whatever).
note: I've left the times (which are in hours) un-added for illustration purposes.