2011-05-26 64 views
1

我需要一種方法來查看超額預定的給定資源(在本例中爲客房/牀)。這是我的表格結構。很抱歉的匈牙利命名法:SQL調度 - 超額預訂報告

tblRoom
--RoomID

tblBooking
--BookingID
--BeginDate
--EndDate
--AssignedRoomID(外鍵)

我沒有任何非工作的SQL在這裏發佈,因爲我真的不知道從哪裏開始。我正在使用MS Access,但如果可能的話,我正在尋找數據庫不可知的解決方案。可以不得不更改某些關鍵字以匹配給定SQL引擎的方言,但我希望避免使用專有的或僅在一個RDBMS中可用的其他功能。

我意識到最好避免從一開始就超量預訂,但這不是這個問題的要點。

如果有幫助,幾天前我發佈了一個相關問題,關於如何查找尚未針對給定數據範圍預訂的資源。你可以看到這個問題here

EDIT1:
在回答下面的答案,我已經修改了你的SQL略,使其在訪問工作,以及當它涉及到的檢測衝突的更準確。如果我錯誤地發現您的解決方案不允許您發現一些衝突,但是當給定的預訂結束日期和不同的預訂開始日期同一天發生衝突時,也會顯示衝突,這實際上是允許的,並且不應該表現爲衝突。我是否正確理解這一點,或者我在這裏錯過了什麼?

SELECT 
    * 
FROM 
    tblBooking AS booking 
INNER JOIN 
    tblBooking AS conflict 
    ON [conflict].AssignedRoomID = [booking].AssignedRoomID 
    AND (([conflict].BeginDate >= DateAdd("d", -1, [booking].BeginDate) AND [conflict].BeginDate < [booking].EndDate) 
    OR ([conflict].EndDate > [booking].BeginDate AND [conflict].EndDate < [booking].EndDate)) 
    AND [conflict].BookingID <> [booking].BookingID 
+0

您已經做了一些改變來打破邏輯。您在預訂過程中檢查衝突的開始或結束是否發生,但如果衝突在預訂之前開始並在之後結束會怎麼樣?你需要對我的示例代碼進行的唯一修改是將'> ='更改爲'>',將<='更改爲'<'。 – MatBailie 2011-05-27 08:25:00

+0

在我的第一個示例中更改<= and > =後,您是否可以顯示某些不應顯示的情況,以及某些應該顯示時未顯示的情況? – MatBailie 2011-05-27 08:27:29

回答

1

那麼,你要找的是tblBooking中的任何記錄,其中有一個重疊期間的AssignRoomID相同的另一條記錄?

一個天真的解決辦法是......

SELECT 
    * 
FROM 
    tblBooking [booking] 
INNER JOIN 
    tblBooking [conflict] 
    ON [conflict].AssignedRoomID = [booking].AssignedRoomID 
    AND [conflict].BeginDate  <= [booking].EndDate 
    AND [conflict].EndDate  >= [booking].BeginDate 
    AND [conflict].BookingID  != [booking].BookingID 

最後一個條件停止預約被它自己的衝突。它也可以改爲AND [conflict].BookingID > [booking].BookingID,這樣你就不會重複衝突。 (如果A與B的衝突,你只能得到A,B,而不是B,A。)


編輯

與上述解決方案的問題是,它沒有很好地進行縮放。當搜索衝突時,該房間的所有預訂都會在預訂的結束日期之前找到,然後根據EndDate進行過濾。幾年後,首次搜索(希望使用索引)將返回許多許多記錄。

一種優化是有一個最大長度預約,並且只能看多天回來的時間衝突...

INNER JOIN 
    tblBooking [conflict] 
    ON [conflict].AssignedRoomID = [booking].AssignedRoomID 
    AND [conflict].BeginDate  <= [booking].EndDate 
    AND [conflict].BeginDate  >= [booking].BeginDate - 7  -- Or however long the max booking length is 
    AND [conflict].EndDate  >= [booking].BeginDate 
    AND [conflict].BookingID  != [booking].BookingID 

具有包裹>=[conflict].BeginDate周圍<=,索引搜索現在可以快速返回合理限制的記錄數。

對於長於最大預訂長度的預訂,可以將它們作爲多個預訂輸入到數據庫中。這就是最優化的技術進來,它往往是所有關於權衡和妥協:)


編輯

另一種選擇,讓不同的細節,將加入預約對日曆表。 (例如,每天有一條記錄。)

SELECT 
    [room].RoomID, 
    [calendar].Date, 
    COUNT(*)      AS [total_bookings], 
    MIN([booking].BookingID)  AS [min_booking_id], 
    MAX([booking].BookingID)  AS [max_booking_id] 
FROM 
    [calendar] 
CROSS JOIN 
    tblRoom  [room] 
INNER JOIN 
    tblBooking [booking] 
    ON [booking].AssignedRoomID = [room].RoomID 
    AND [booking].BeginDate  <= [calendar].Date 
    AND [booking].EndDate  >= [calendar].Date 
GROUP BY 
    [room].RoomID, 
    [calendar].Date 
HAVING 
    COUNT(*) > 1 
+0

我正在測試您的答案,特別是第一個答案,以便在我開始使用其他想法之前,確保其能夠按預期工作。我遇到一些問題,因爲預訂開始數據可以與另一個預訂結束日期重疊。 – HK1 2011-05-26 19:28:32

+0

這應該很簡單。改變'<=' and '> ='應該只是'<' and '>'。 – MatBailie 2011-05-26 22:04:04