MySQL / PHP - 查找可用时间段

5

有一些类似的问题被提出,但我找不到这个具体问题的解决方案,感激您的帮助。

我正在开发一个预订引擎,用户可以在线预订某些服务。我现在需要找到并显示特定日期(或一周内)内可用的时间段。我知道所需时间段的长度(例如1小时),以及可预订时间段的营业时间(例如09:00-18:00)。此外,我还有一个MySQL表格,用于存储已经存在的预约。与我提出问题相关的列如下:

id  start (datetime)        end (datetime)
1   '2012-11-16 13:00:00'   '2012-11-16 14:30:00'
2   '2012-11-16 15:00:00'   '2012-11-16 16:00:00'
3   '2012-11-17 12:00:00'   '2012-11-16 15:45:00'
4   '2012-11-17 13:00:00'   '2012-11-16 16:15:00'
...

现在根据上述信息,我无法找到一个好的解决方案(在MySQL或PHP中)来检索可用时间段列表。还有一个条件:时间段只能按季度开始。即,对于上面的示例数据,在第16个可用的一小时时间段将是:
09:00、09:15、09:30、09:45、10:00,...,12:00,16:00,16:15,...,17:00。

请注意,即使可能存在重叠时间(如样本数据),可用时间段也不能重叠。

您认为最好的方法是什么?

重叠的条件是什么?它们是针对与一个人预订服务的情况,还是可以同时发生多个约会? - Lucas
这是为一个人预订的。普通用户只能预订100%空闲的时间段,即没有重叠。管理员有一个不同/更复杂的日历,允许重叠(因为他们可能知道在某些情况下可以处理重叠)。对于上面的问题,我想唯一重要的点是数据库表中可能存在重叠的时间段,系统应该尝试找到可用性。 - j2dab
1个回答

8
SELECT a.end AS free_after
FROM bookings a
WHERE NOT EXISTS (
  SELECT 1
  FROM bookings b
  WHERE b.start BETWEEN a.end AND a.end + INTERVAL your_duration HOURS
)
AND a.end BETWEEN start_of_search_window AND end_of_search_window;

你只需要提供 your_duration(整数)、start_of_search_window(日期时间)和 end_of_search_window(日期时间)的值。
如果你想要更多功能...
SELECT free_from, free_until
FROM (
  SELECT a.end AS free_from,
  (SELECT MIN(c.start)
   FROM bookings c
   WHERE c.start > a.end) as free_until
  FROM bookings a
  WHERE NOT EXISTS (
    SELECT 1
    FROM bookings b
    WHERE b.start BETWEEN a.end AND a.end + INTERVAL your_duration HOUR
  )
  AND a.end BETWEEN start_of_search_window AND end_of_search_window
)
ORDER BY free_until-free_from
LIMIT 0,3;

将为您提供窗口内三个最短的可用插槽(即最接近目标尺寸)。

1
非常好,非常感谢!这正是我要找的!您认为是否也可能将结果作为所有可用插槽呈现?在上面的示例中,一个结果行是:2012-11-16 16:00:00 - 2012-11-17 12:00:00。与此不同,我更喜欢包含时间段的多行,例如:2012-11-16 16:00:00 - 2012-11-16 17:00:00和2012-11-16 17:00:00 - 2012-11-16 18:00:00等等...或者您会使用PHP将整个空闲时间分成插槽吗? - j2dab
1
还有一件事,我已经尝试了你的解决方案,但发现一个棘手的问题我自己无法解决。如果我使用你的语句,并将start_of_search_window设置为2012-11-16 00:00:00,end_of_search_window设置为2012-11-18 00:00:00,则会错过2012-11-16 00:00:00和2012-11-16 13:00:00之间的空闲时间块。也就是说,它只会在找到第一个约会后才开始查找free_from。你能指导我如何修复这个bug吗? - j2dab
从概念上来说,这很简单 - 只需用包括在您的窗口开始处结束的虚拟约会替换“预订a”表中的视图即可,但SQL则更加复杂。 - symcbean
1
可能很简单,但我无法为此查询设置上限和下限。 - Aramil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接