Как найти максимальную доступную емкость в перекрывающиеся периоды времени SQL Server 2008 - PullRequest
3 голосов
/ 29 февраля 2012

Мы работаем над системой бронирования номеров, в которой один и тот же номер может быть забронирован разными людьми до тех пор, пока вместимость не будет превышена.

Мы пытаемся рассчитать максимальное количество мест, доступных длявесь период времени, запрашиваемый для нового бронирования.

Это, вероятно, лучше всего объяснить диаграммой.Предположим, что эта комната вмещает 100:

<-------I want to book this - How many seats are available?------->

   <---Booking 1: 10 seats--->       <---Booking 2: 10 seats--->
                       <---Booking 3: 10 seats--->
                                     <---Booking 4: 10 seats--->

Таким образом, минимальное максимальное количество, доступное в любой момент времени в течение запрошенного периода, будет 70 (Бронирования 2, 3 и 4 перекрывают друг друга, забирая 30 мест из строя в это время).

Как это можно рассчитать с помощью SQL?Мы хотим, чтобы запрос возвратил количество мест, доступных в настоящее время для запрошенного временного интервала, в указанном выше случае 70.

Доступны следующие таблицы: RoomBooking (room, start, end ,acity_taken) и Room (id ,acity)).

Мы используем SQL Server 2008.

Ответы [ 3 ]

4 голосов
/ 29 февраля 2012

Для определенного @room и периода времени от @start_time до @end_time, попробуйте:

;with cte as 
(select id, capacity, @start_time time_point
 from room where id = @room
 union all
 select id, capacity, dateadd(mi, 1, time_point) time_point
 from cte where dateadd(mi, 1, time_point) < @end_time)
select min(capacity_left) max_available from
(select c.time_point, max(c.capacity) - sum(b.capacity_taken) capacity_left
 from cte c
 join RoomBooking b
   on c.id = b.room and
      c.time_point >= b.start and
      c.time_point < b.end
 group by c.time_point) sq

Обратите внимание, что максимальная вместимость, которая будет доступна в течение всего периода бронирования весь , составляет наименьшую доступную вместимость в любой точке периода - поэтому в примере это будет 70 мест .

1 голос
/ 29 февраля 2012

Должен быть способ уникальной идентификации каждого бронирования.Я бы предложил добавить столбец идентификаторов в таблицу RoomBooking и решить проблему, как показано в коде ниже:

create table Room
(
    id int identity(1, 1) primary key clustered,
    capacity int not null
)
go
create table RoomBooking
(
    id int identity(1, 1) primary key clustered,
    room int constraint FK_RoomBooking_Room foreign key references Room(id),
    start_time datetime,
    end_time datetime,
    capacity_taken int
)
go

insert Room(capacity)
    select 100 union all
    select 200

insert RoomBooking(room, start_time, end_time, capacity_taken)
    select 1, '2012-02-29 10:00', '2012-02-29 12:00', 10 union all
    select 1, '2012-02-29 11:00', '2012-02-29 15:00', 10 union all
    select 1, '2012-02-29 14:00', '2012-02-29 16:00', 10 union all
    select 2, '2012-02-29 14:00', '2012-02-29 16:00', 10 union all
    select 2, '2012-02-29 14:00', '2012-02-29 16:00', 10 union all
    select 2, '2012-02-29 14:00', '2012-02-29 16:00', 10 union all
    select 2, '2012-02-29 13:00', '2012-02-29 15:00', 10 union all
    select 2, '2012-02-29 15:00', '2012-02-29 17:00', 10 union all
    select 2, '2012-02-29 17:00', '2012-02-29 19:00', 10 union all
    select 1, '2012-02-29 14:00', '2012-02-29 16:00', 10

go

declare @roomid int = 1
declare @check_period_start datetime = '2012-02-29 13:00'
declare @check_period_end datetime = '2012-02-29 15:00'

select
    r.id, r.capacity - maxtaken.max_capacity_taken as remaining_capacity
from
    Room r
    join
        (
            select
                id, MAX(sum_capacity_taken) max_capacity_taken
            from
                (
                    select
                        r.id, SUM(rb2.capacity_taken) + min(rb1.capacity_taken) sum_capacity_taken
                    from
                        Room r
                        join RoomBooking rb1 on rb1.room = r.id
                        left join RoomBooking rb2
                            on rb1.room = rb2.room
                               and rb1.id <> rb2.id
                               and 
                               (
                                   (rb2.start_time <= rb1.start_time and rb2.end_time >= rb1.start_time)
                                   or (rb2.start_time <= rb1.end_time and rb2.end_time >= rb1.end_time)
                               )
                        where
                            rb1.end_time >= @check_period_start
                            and rb1.start_time <= @check_period_end
                            and rb2.end_time >= @check_period_start
                            and rb2.start_time <= @check_period_end
                        group by
                            r.id, rb1.id
                ) sct
                group by id
        ) maxtaken on maxtaken.id = r.id
where
    r.id = @roomid
0 голосов
/ 29 февраля 2012

Вот один из подходов. Сначала я создаю список часов, которые ставят под угрозу назначение, используя рекурсивный КТ под названием «часы». Затем для каждого часа CTE "hour_capacity" суммирует количество забронированных мест. В последнем запросе подсчитывается количество мест, которые не используются каждый час.

; with  hours as
        (
        select  @startdt as dt
        union all
        select  dateadd(hour, 1, dt)
        from    Hours
        where   dateadd(hour, 1, dt) < @enddt
        )
,       hour_capacity as
        (
        select  h.dt
        ,       r.capacity
        ,       sum(b.seats) as seats_used
        from    @room r
        cross join
                hours h
        join    @booking b
        on      b.roomid = r.id
                and h.dt between b.startdt and b.enddt
        where   r.id = @roomid
        group by
                h.dt
        ,       r.capacity
        )
select  capacity - max(seats_used)
from    hour_capacity
group by
        capacity

Полный пример в данных SE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...