在预订系统中查找免费插槽

时间:2009-04-23 10:57:49

标签: sql mysql django date

my question about searching for date ranges中,我尝试简化问题,无意中提出了一个不同且更简单的问题。

不是通过编辑使这个问题复杂化,而是要问我实际想要的问题。

我有两张表属性和预订。预订具有属性的外键以及开始和结束日期。

用户正在搜索空闲广告位并以天为单位提供所需的持续时间。他们还提供他们感兴趣的一系列开始日期。因此,搜索将按以下方式进行: “找到我所有的房产我想要一个3天的时间段,从5月开始。”

现在我可以这样做: 1.为每个潜在的开始日运行31个查询 2.查找5月份的所有预订,将它们压缩成一个31个布尔值的数组,代表天数,然后循环查找插槽。

我认为(2)在大多数情况下效率更高。有没有更好的算法?是否有纯SQL解决方案。

我将使用Django并且我的数据集很小所以我可能会对'哑'approuch感到满意,但我很想知道最好的算法是什么样的。

2 个答案:

答案 0 :(得分:4)

你的申请可能有点过分 - 但是:

以“写入”过程变得更加复杂为代价来改进搜索的一种相对简单的方法是更改​​Booking表,使其成为“可用性”表。

添加一个布尔列以指示该插槽是空闲还是已预订(或者更好地保留在预订它的客户的ID中,如果插槽空闲则使用0)。

从一个免费插槽开始,2009年1月1日 - > 12月31日???

当您预订时,将免费插槽分为3个(两个插入和一个更新),预订的插槽和两个可用插槽。

继续这样做,随着时间框架变得更加分散,预订流程将包含以下其中一项:

  • 将某个“可用位置”分配给某人(一次更新)
  • 将“可用插槽”拆分为两个(一个更新和一个插入)
  • 如果有人从可用插槽中读出中间部分,则将插槽拆分为3(如上所述)。

管理并不是非常复杂,搜索过程变成了一个简单的查询:在所需的时间范围内找到任何可用的插槽(预订= false或customerid = 0,无论你采用哪种方式),其中enddate - startdate&gt ; =您想要的天数。

它使预订/可用性表的大小翻倍,并使预订变得不那么简单,但权衡的是搜索过程就像它一样容易。

答案 1 :(得分:4)

表定义会有所帮助,但这里有所帮助。这应该适用于MS SQL Server,但是一旦理解了它背后的想法,将它转换为MySQL应该是一项微不足道的任务。

Calendar表只是一个标准的实用程序表,其中包含数据库中的所有日期。如果您还没有,我建议您创建一个并填充它。

CREATE TABLE Calendar
(
     date        DATETIME     NOT NULL,
     is_holiday  BIT          NOT NULL,
     -- any other columns that might be relevant for your business
     CONSTRAINT PK_Calendar PRIMARY KEY CLUSTERED (date)
)

然后,您需要使用可能对您的业务有意义的任何日期填充表格。即使您回溯100年并向前走100年,表中的行仍然少于75K,并且它集中在日期,因此它应该快速且易于使用。它使许多基于日期的查询更加简单。

SELECT
     P.property_id,
     C.date
FROM
     Calendar C
JOIN Properties P ON 1=1
WHERE
     C.date BETWEEN @search_start_date AND @search_end_date AND
     NOT EXISTS
     (
          SELECT
               *
          FROM
               Bookings B
          WHERE
               B.property_id = P.property_id AND
               B.start_date <= DATEADD(dy, @slot_length, C.date) AND  -- You would use MySQLs date function
               B.end_date   >= C.date
     )

或者:

SELECT
     P.property_id,
     C.date
FROM
     Calendar C
JOIN Properties P ON 1=1
LEFT OUTER JOIN Bookings B ON
               B.property_id = P.property_id AND
               B.start_date <= DATEADD(dy, @slot_length, C.date) AND  -- You would use MySQLs date function
               B.end_date   >= C.date
WHERE
     C.date BETWEEN @search_start_date AND @search_end_date AND
     B.booking_id IS NULL