2009-04-23 40 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