SQL调度 - 超量预定报告

时间:2011-05-26 13:27:45

标签: sql ms-access

我需要一种方法来查看超额预订的给定资源(在本例中为房间/床)。这是我的表格结构。抱歉匈牙利语符号:

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

1 个答案:

答案 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