在 mysql 中的特定时间后获取下一个可用时间段

Get next available time slot after a certain time in mysql

我正在尝试通过检查 table 中的保留时间列表来获取下一个可用时间段。每次预订最少可以增加 1 小时,并且可以持续一整天。例如,如果房间是从上午 9 点到 10 点,以及从中午 12 点到下午 3 点预订的,我想在上午 9 点之后获得第一个可用空位。现在是上午 10 点。

我可以在 table 上离开加入并获得房间可用性,但不是时间段。

这是我的相关架构:

预订

res_id | hotel_id | room_id | res_start | res_end

房间数:

room_id | hotel_id | room_name | room_number

这是我目前的查询:

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

但是我从它那里得到了错误的返回时间。

预期结果:

room_id | room_name | Next available time
1       | "Single"  | 2019-01-05 10:00:00

这是一个time_slotstable

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');

您可以使用相关子查询来过滤掉紧接着另一个预订的预订;聚合外部查询 returns 每个房间的较早可用时间段。

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

测试于 this DB fiddle

我假设在连接表时要使用的 hotel_idroom_id 列(如果 room_id 就足够了,那会稍微缩短查询)。

我想这个查询会给你想要的结果。它会查找晚于当前时间的任何预订,其 res_end 没有匹配的 res_start 另一个预订。

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

输出(对于我的小demo on dbfiddle):

room_id     room_name   available from
1           Single      2019-01-06 10:00

更新

此查询使用时间段 table 来考虑在感兴趣的时间开始时房间内没有预订的情况:

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

您可以将此查询中的 @time 替换为您感兴趣的时间。我已经更新了我的 demo on dbfiddle 来演示查询,您可以尝试调整 @time 变量来观察它的工作。