[英]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.