我需要一种方法来查看超额预订的给定资源(在本例中为房间/床)。这是我的表格结构。抱歉匈牙利语符号:
tblRoom
--RoomID
tblBooking
--BookingID
--BeginDate
--EndDate
--AssignedRoomID(外键)
我没有任何非工作的SQL在这里发布,因为我真的不知道从哪里开始。我正在使用MS Access,但如果可能的话,我正在寻找与数据库无关的解决方案。可以不得不更改某些关键字以匹配给定SQL引擎的方言,但我想避免使用其他专有或仅在一个RDBMS中可用的功能。
我意识到最好避免从一开始就超量预订,但这不是这个问题的重点。
如果它有用,我几天前发布了一个相关问题,关于如何查找尚未针对给定数据范围预订的资源。您可以看到问题here。
EDIT1:
在回答下面的答案时,我略微修改了SQL,使其在Access中工作,并在检测冲突时更准确。如果我不错,下面发布的解决方案允许一些冲突被忽视,但当给定的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
答案 0 :(得分: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之前,然后根据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