[英]SQL Scheduling - Overbooked Report
我需要一種方法來查看超額預訂的給定資源(在本例中為房間/床位)。 這是我的表結構。 對不起匈牙利符號:
房間
--房間ID
tblBooking
--BookingID
--開始日期
- 結束日期
--AssignedRoomID(外鍵)
我沒有任何不工作的 SQL 可以在這里發布,因為我真的不知道從哪里開始。 我正在使用 MS Access,但如果可能的話,我正在尋找與數據庫無關的解決方案。 必須更改一些關鍵字以匹配給定 SQL 引擎的方言是可以的,但我想避免使用其他專有功能或僅在一個 RDBMS 中可用。
我意識到最好從一開始就避免超額預訂,但這不是這個問題的重點。
如果它有幫助,我幾天前發布了一個相關問題,關於如何查找尚未為給定數據范圍預訂的資源。 你可以在這里看到這個問題。
編輯1:
在回復下面的答案時,我稍微修改了您的 SQL 以使其在 Access 中工作以及在檢測沖突時更准確。 如果我錯了,您在下面發布的解決方案允許與 go 發生一些沖突而不引起注意,但當給定的 Booking 的 EndDate 和不同的 Booking 的 BeginDate 落在同一天時也會顯示沖突,這實際上是允許的,不應顯示為沖突。 我是否正確理解這一點,或者我在這里遺漏了什么?
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
那么,您要查找的是 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 之前找到,然后根據 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
周圍包裹>=
AND a <=
,索引搜索現在可以快速返回合理有限數量的記錄。
對於超過最大預訂長度的預訂,可以將它們作為多個預訂輸入數據庫。 這就是優化藝術的用武之地,它通常都是關於權衡和妥協:)
編輯
提供不同詳細信息的另一種選擇是將預訂加入日歷表。 (例如,每天有一條記錄。)
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.