2012-06-14 84 views
2

我正在用PHP和MySQL構建一個簡單的可用性日曆。MySQL可用性日曆 - 計算免費日期的方法?

我已存儲的可用日期爲屬性表(目前個個都是7天塊)

available_dates: 
    start_date DATE 
    end_date  DATE 
    available_id INT PRIMARY KEY 
    property_id INT 
    booked  TINYINT(1) 

並預訂日期的表,它引用了我的available_datesavailable_id

bookings 
    booking_id INT 
    available_id INT 

    ***user details*** 

我打算爲每個屬性添加行,以標記哪些日期可以預訂,然後在有人預訂時設置預訂標誌。

我想要做的是顯示沒有可用性設置的日期列表(在x天內,在這種情況下爲7塊),因此日期不會顯示在該表中 - 在接下來的24個月或者。

我有麻煩纏繞在此我的頭,我知道還有一個更簡單的方式來做到這一點,我通過每個屬性,然後每7天循環塊,等等等等

的第一想法

任何人都可以啓發我嗎?


更新:

由於@ZaneBien的輝煌和全面的答覆,我設法用他yeardate表&程序得到我需要的結果。 我所做的是當需要顯示沒有可用性設置的日期的頁面被請求時,如果CURYEAR()+2沒有任何值,PHP會調用該過程來添加更多的yeardates。

然後讓我的結果,贊恩的查詢稍加修改的版本:

SELECT 
    a.yeardate AS blockstart, 
    DATE_ADD(a.yeardate, INTERVAL 7 DAY) AS blockend 
FROM 
    yeardates a 
LEFT JOIN 
    available_dates b 
     ON(a.yeardate BETWEEN b.start_date AND b.end_date)    
    OR  
    (DATE_ADD(a.yeardate, INTERVAL 7 DAY) BETWEEN b.start_date AND b.end_date) 
WHERE 
    b.date_id IS NULL AND WEEKDAY(a.yeardate)=5; 

在我的情況下,該塊是7天,週六至下週六 - 所以我增加了第二WHERE子句查詢這樣我就可以在每星期六的星期六到星期六的每個星期六之間得到不同的結果。

所以不是:

+------------+------------+ 
| blockstart | blockend | 
+------------+------------+ 
| 2012-01-01 | 2012-01-08 | 
| 2012-01-02 | 2012-01-09 | 
| 2012-01-03 | 2012-01-10 | 
| 2012-01-04 | 2012-01-11 | 

我得到這個:

+------------+------------+ 
| blockstart | blockend | 
+------------+------------+ 
| 2012-01-07 | 2012-01-14 | 
| 2012-01-14 | 2012-01-21 | 
| 2012-01-21 | 2012-01-28 | 
| 2012-01-28 | 2012-02-04 | 

這是正是我需要什麼。再次感謝Zane提供了一個很好的答案。

+0

因此,在用戶預訂日期塊(將新記錄插入到預訂表中)後,您是否立即將該日期的預訂標誌設置爲1?另外,如果用戶預定3周,你會怎麼做?他們可以嗎?您是否在預訂表中插入3行來預訂3個區塊中的每一個? –

+0

最初在閱讀你的問題之後,我以爲你只是想要所有'available_dates'中沒有預訂的記錄(WHERE預訂= 0或NOT IN等),但仔細閱讀後,我會想*你想要什麼在接下來的兩個**年中**都是7天的**,**在'availability_dates'表中不是**。它是否正確? –

+0

@ZaneBien是的,他們可以預訂> 1日期,預訂的每個區塊將在預訂表中排成一行。是的,我知道這不是最清晰的問題,這個問題相當複雜(至少對我來說),但你得到它的要點:) – jammypeach

回答

2

的記錄理解你作爲問題檢索其範圍內的當前和明年的全部7天的間隔塊不重疊任何間隔塊已經在available_dates現有:

要與當前和明年的每一天的工作,我們要創建一個包含DATE S的所有當前天一個單獨的表(yeardates)和明年。這將有助於我們在檢索查詢中操作OUTER JOIN

代碼來定義yeardates表並插入日期:

CREATE TABLE yeardates 
(
    yeardate DATE NOT NULL, 
    PRIMARY KEY (yeardate) 
) ENGINE = MyISAM; 

DELIMITER $$ 
CREATE PROCEDURE PopulateYear(IN inputyear INT) 
    BEGIN 
     DECLARE i INT; 
     DECLARE i_end INT; 
     SET i = 1; 
     SET i_end = CASE WHEN inputyear % 4 THEN 365 ELSE 366 END; 
     START TRANSACTION; 
     WHILE i <= i_end DO 
      INSERT INTO yeardates VALUES (MAKEDATE(inputyear, i)); 
      SET i = i + 1; 
     END WHILE; 
     COMMIT; 
    END$$ 
DELIMITER ; 

CALL PopulateYear(2012); 
CALL PopulateYear(2013); 

表,然後創建包含當前和明年的每一天。如果我們需要在隨後幾年插入日期,只需CALL該過程再以年份作爲參數(例如2014,2015等)。

然後我們就可以得到7天的塊不中available_dates表重疊塊:

SELECT 
    a.yeardate AS blockstart, 
    DATE_ADD(a.yeardate, INTERVAL 7 DAY) AS blockend 
FROM 
    yeardates a 
LEFT JOIN 
    available_dates b ON 
     (a.yeardate BETWEEN b.start_date AND b.end_date) 
     OR 
     (DATE_ADD(a.yeardate, INTERVAL 7 DAY) BETWEEN b.start_date AND b.end_date) 
WHERE 
    b.available_id IS NULL 

檢索基礎上所有性質預訂所有的7天免費塊,但如果我們需要得到的只是一個特定屬性的7天免費塊,我們可以使用:

SELECT 
    a.yeardate AS blockstart, 
    DATE_ADD(a.yeardate, INTERVAL 7 DAY) AS blockend 
FROM 
    yeardates a 
LEFT JOIN 
    (
     SELECT * 
     FROM available_dates 
     WHERE property_id = <property_id here> 
    ) b ON 
     (a.yeardate BETWEEN b.start_date AND b.end_date) 
     OR 
     (DATE_ADD(a.yeardate, INTERVAL 7 DAY) BETWEEN b.start_date AND b.end_date) 
WHERE 
    b.available_id IS NULL 

哪裏<property_id here>是PROPERTY_ID。我們甚至可以通過簡單地將其更改爲WHERE property_id IN (<comma sep'd list of property_ids here>)來同時進行基於多個屬性的選擇。

+0

這是一個非常好的解決方案,正是我所要求的,謝謝。我會給它一個鏡頭,並接受,如果一切順利:) – jammypeach

+0

這幫了我,再次感謝。儘管我會對最後一個查詢做一些修改,但我會在更新完成後更新:) – jammypeach

+1

太棒了!我很高興你得到了你需要的結果。我知道這是挑剔的......但在你修改後的查詢中,這不是對'HAVING'子句的正確使用。如果'blockstart'是一個計算值,可能可以理解,因爲最後評估了HAVING,但在你的情況下,'blockstart'只是'a.yeardate'的別名(你仍然可以訪問它,甚至混淆後)。 'GROUP BY'也是不必要的,因爲'a.yeardate'值是唯一的。因此,作爲最終建議,在'WHERE'中取出GROUP BY和HAVING,並將'WEEKDAY(a.yeardate)= 5'作爲第二個條件檢查。 –

0

我認爲你已經倒退了。

所有時間都可能提供,除非預訂一空,什麼已經預訂在數據庫中,敲那些你的結果

+0

這是問題的一部分 - 所有日期*不是*可能avaialable除非預訂 - 在這種情況下,只能預訂一年中的某些周。否則我會按照你的方式去做。那麼如果不記錄可用日期,我應該如何處理它? – jammypeach