Reputation: 508
I am trying to get the next available time slot by checking the list of reserved times in the table. Each reservation can be minimam of 1 hour incrementation and gcan go on all day. So for example, if the room is booked from 9 AM to 10 AM, and from 12 AM to 3 PM and I am trying to get the first available slot after 9 am. It will be 10 am.
I am able to left join on the table and get the room availability but just not the time slots.
Here is my related schema:
Reservations
res_id | hotel_id | room_id | res_start | res_end
Rooms:
room_id | hotel_id | room_name | room_number
Here is the query I have so far:
SELECT free_from, free_until
FROM (
SELECT a.res_end AS free_from,
(SELECT MIN(c.res_start)
FROM reservations c
WHERE c.res_start > a.res_end) as free_until
and b.res_end > "2019-01-05 11:00:00"
FROM reservations a
WHERE NOT EXISTS (
SELECT 1
FROM reservations b
WHERE b.res_start > a.res_end
)
) as d
ORDER BY free_until-free_from
But I am getting the wrong time returned from it.
Expected result:
room_id | room_name | Next available time
1 | "Single" | 2019-01-05 10:00:00
Here is a time_slots table
CREATE TABLE time_slots
(`slot` time);
INSERT INTO time_slots
(`slot`)
VALUES
('00:00:00'),
('01:00:00'),
('02:00:00'),
('03:00:00'),
('04:00:00'),
('05:00:00'),
('06:00:00'),
('07:00:00'),
('08:00:00'),
('09:00:00'),
('10:00:00'),
('11:00:00'),
('12:00:00'),
('13:00:00'),
('14:00:00'),
('15:00:00'),
('16:00:00'),
('17:00:00'),
('18:00:00'),
('19:00:00'),
('20:00:00'),
('21:00:00'),
('22:00:00'),
('23:00:00');
Upvotes: 0
Views: 1074
Reputation: 147166
I think this query will give you the results you want. It looks for any reservation later than the current time whose res_end
has no matching res_start
for another reservation.
SELECT rm.room_id, rm.room_name, MIN(re.res_end) AS `available from`
FROM reservations re
LEFT JOIN reservations rs ON rs.hotel_id = re.hotel_id AND rs.room_id = re.room_id AND rs.res_start = re.res_end
JOIN rooms rm ON rm.hotel_id = re.hotel_id
WHERE rs.res_id IS NULL AND re.res_end > NOW()
GROUP BY rm.room_id, rm.room_name
Output (for my small demo on dbfiddle):
room_id room_name available from
1 Single 2019-01-06 10:00
Update
This query uses a timeslot table to allow for the case where there are no reservations in a room when the time of interest starts:
SELECT rm.room_id, rm.room_name,
MIN(t.slot) AS `available from`
FROM time_slots t
CROSS JOIN rooms rm
LEFT JOIN reservations r ON HOUR(t.slot) BETWEEN HOUR(r.res_start) AND HOUR(r.res_end) - 1
AND DATE(r.res_start) = DATE(@time)
AND r.hotel_id = rm.hotel_id
AND r.room_id = rm.room_id
WHERE t.slot > @time AND r.res_id IS NULL
GROUP BY rm.room_id, rm.room_name
ORDER BY rm.room_id
You would replace @time
in this query with your time of interest. I've updated my demo on dbfiddle to demonstrate the query, you can play with adjusting the @time
variable to watch it work.
Upvotes: 1
Reputation: 222482
You can use a correlated subquery to filter out reservations that are immediately followed by another one ; the aggregated outer query returns the earlier available timeslot for each room.
SELECT
roo.hotel_id,
roo.room_id,
roo.room_name,
MIN(res.res_end) next_available_time
FROM
reservations res
INNER JOINS rooms roo
ON roo.hotel_id = res.hotel_id
AND roo.room_id = res.room_id
WHERE
res.res_end > "2019-01-05 11:00:00"
AND NOT EXISTS (
SELECT 1
FROM reservations
WHERE
res_start = res.res_end
AND hotel_id = res.hotel_id
AND room_id = res.room_id
)
GROUP BY
res.hotel_id,
res.room_id,
roo.room_name
Tested in this DB fiddle.
I assumed that both columns hotel_id
and room_id
where to be used when joining tables (if room_id
was enough, that would shorten the query a little).
Upvotes: 1