Итак, что вам нужно, это любая запись в 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
.)
EDIT
Проблема с вышеуказанным решением состоит в том, чтоэто не очень хорошо масштабируется.При поиске Конфликта все бронирования для этой комнаты перед тем, как будет найдена конечная дата бронирования, затем отфильтрованы на основе конечной даты.Через несколько лет этот первый поиск (возможно, с использованием индекса) вернет много-много записей.
Одна из оптимизаций заключается в том, чтобы иметь максимальную продолжительность бронирования и искать только столько дней назад во время конфликта...
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