2009-04-23 73 views
1

my question about searching for date ranges我尝试简化问题并无意间提出了另一个更简单的问题。在预约系统中查找免费插槽

而不是通过编辑使问题复杂化,我会问我实际打算的问题。

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

用户正在搜索空闲插槽并以天为单位提供所需的持续时间。他们还提供他们感兴趣的一系列开始日期。因此,搜索将沿着以下方向进行: “找到我想要的所有房产我想要一个3天的时间段,它可以在5月的任何时候开始。”现在

我可以做到这一点: 1.运行对每个可能的开始日期 2.查找所有预订5月31日查询,精简为代表天,环31个布尔一个阵列通过寻找插槽。

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

我将使用Django,而且我的数据集很小,所以我可能会用'笨'的approuch,但我很想知道最好的算法是什么样子。

回答

4

为您的应用程序可能矫枉过正 - 但是:

一个相对简单的是使“写”的过程更加复杂的代价提高你的搜索的方式,将是改变的预订表,使之成为“可用性'表。

添加一个布尔列来指示插槽是空闲还是预订(或者更好的是放入预订客户的ID,如果插槽是空闲的,则使用0)。

从2009年1月1日至12月31日的单个空闲位置开始。

当您获得预订时,将空闲插槽分为3个(两个插入和一个更新),已预订的插槽和两个可用插槽。

继续这样做,并随着时间的框架变得更加支离破碎预订过程将包括以下之一:

  • 分配整个“可用插槽”的人(一个更新)
  • 分割的'可用插槽'分成两部分(一个更新和一个插入)
  • 如果有人从可用插槽中预订中间部分,则将插槽拆分为3(如上所述)。

这不是令人难以置信的复杂的管理和搜索过程变得简单的查询:找到任何插槽所需的时间框架可用(预订=虚假或客户id = 0,你去用它无论怎样),其中ENDDATE - startdate> =你想要的天数。

它使预订/可用性表的大小加倍,并且使预订变得不那么简单,但是折衷是搜索过程非常简单。

+0

很聪明的做法,但我需要许多其他用途的预订数据量太大。除了我目前的预订模式之外,我还可以为每个房产提供可用性表。这在某种意义上反规范化了我的数据,使得一种搜索更容易,但在这种情况下,可以算作过早的优化。 – 2009-04-23 11:59:43

+0

您的原始预订数据仍然存在 - 它只是有一个额外的列,其中包含'预订'布尔或customerid。如果您在预订= true或客户端> 0的情况下搜索可用性表,则您的记录集与原始表中的记录集相同。这就是它将桌子大小加倍的原因,它包括预订和可用的插槽。 – 2009-04-23 12:09:35

4

表格定义会有帮助,但在这里。这应该适用于MS SQL Server,但一旦理解其背后的想法,将其转换为MySQL应该是一件简单的任务。

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

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