我们正在开设一个房间预订系统,只要不超过容量,就可以由不同的人预订同一个房间。
我们正在尝试计算新预订所需的整个时间段内的最大座位数。
最好用图表解释。假设这个房间容纳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(房间,开始,结束,capacity_taken)和房间(id,容量)。
我们使用SQL Server 2008。
答案 0 :(得分:4)
对于从@start_time到@end_time的特定@room和时间段,请尝试:
;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 :(得分:1)
应该有一种方法来唯一识别每个预订。我建议在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
答案 2 :(得分:0)
这是一种方法。我首先创建一个使用名为“hours”的递归CT来破坏约会的小时列表。然后,每小时,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