Планирование SQL - переполненный отчет - PullRequest
1 голос
/ 26 мая 2011

Мне нужен способ просмотреть данный ресурс (в данном случае номера / кровати), который перебронирован.Вот моя структура таблицы.Извините за венгерскую нотацию:

tblRoom
--RoomID

tblBooking
--BookingID
--BeginDate
--EndDate
--AssignedRoomID(внешний ключ)

У меня нет нерабочего SQL для публикации здесь, потому что я действительно не знаю, с чего начать.Я использую MS Access, но, если возможно, я ищу независимое от базы данных решение.Можно изменить некоторые ключевые слова, чтобы они соответствовали диалекту данного механизма SQL, но я бы не хотел использовать другие функции, которые являются собственностью или доступны только в одной СУБД.

Я понимаю, что этоЛучше всего избегать перебронирования с самого начала, но суть этого вопроса не в этом.

В случае, если это полезно, пару дней назад я опубликовал связанный вопрос о том, как найти ресурсы, которые еще не забронированы для данных.спектр.Вы можете увидеть этот вопрос здесь .

Edit1:
В ответ на ответ ниже я немного изменил ваш SQL, чтобы он работал в Accessа также чтобы быть более точным, когда дело доходит до выявления конфликтов.Если я не ошибаюсь, ваше решение, опубликованное ниже, позволяет некоторым конфликтам остаться незамеченными, но также показывает конфликты, когда конечная дата данного бронирования и другая дата начала бронирования относятся к одному и тому же дню, что фактически допустимо и не должно отображаться как конфликт.Я правильно понимаю или я что-то здесь упускаю?

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 Ответ

1 голос
/ 26 мая 2011

Итак, что вам нужно, это любая запись в 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...