I have three tables.
- Table (t), a resource in my system. It has a maximum capacity.
- Booking (b), a reservation in the system, it hase FromDatimeTime, ToDateTime and nrOfPeople
- BookedTable (bt), connects the booking with table and how many seats that are used by this booking, a booking can have more than one table.
The problem is that if i have three bookings:
- 4 people comming at 12:00 and leaving at 14:00.
- 4 people comming at 12:00 and leaving at 13:00.
- 4 people comming at 13:00 and leaving at 14:00.
All bookings using the same table with 8 seats. I want to se if the table is "overbooked".
Setup code
CREATE TABLE Tables (
TableNr INT,
Seats INT
)
GO
CREATE TABLE Booking
(
BookingNr INT,
Time_From DATETIME,
Time_TO DATETIME,
Guests INT
)
GO
CREATE TABLE Table_Booking
(
TableBookingId INT ,
BookingNr INT ,
TableNr INT ,
GuestOnTable int
)
GO
INSERT INTO [Tables] ( [TableNr], [Seats]) VALUES ( 1, 8 )
INSERT INTO [Tables] ( [TableNr], [Seats]) VALUES ( 2, 4 )
INSERT INTO [Tables] ( [TableNr], [Seats]) VALUES ( 3, 4 )
INSERT INTO [Booking] ([BookingNr],[Time_From],[Time_TO],[Guests]) VALUES ( /* BookingNr - INT */ 1,/* Time_From - DATETIME */ '2009-7-7 11:00',/* Time_TO - DATETIME */ '2009-7-7 13:00',/* Guests - INT */ 4 )
INSERT INTO [Booking] ([BookingNr],[Time_From],[Time_TO],[Guests]) VALUES ( /* BookingNr - INT */ 2,/* Time_From - DATETIME */ '2009-7-7 11:00',/* Time_TO - DATETIME */ '2009-7-7 12:00',/* Guests - INT */ 4 )
INSERT INTO [Booking] ([BookingNr],[Time_From],[Time_TO],[Guests]) VALUES ( /* BookingNr - INT */ 3,/* Time_From - DATETIME */ '2009-7-7 12:00',/* Time_TO - DATETIME */ '2009-7-7 13:00',/* Guests - INT */ 4 )
INSERT INTO [Table_Booking] ([TableBookingId],[BookingNr],[TableNr], GuestOnTable) VALUES (/* TableBookingId - INT */ 1, /* BookingNr - INT */ 1,/* TableNr - INT */ 1, 4 )
INSERT INTO [Table_Booking] ([TableBookingId],[BookingNr],[TableNr], GuestOnTable) VALUES (/* TableBookingId - INT */ 2, /* BookingNr - INT */ 2,/* TableNr - INT */ 1, 4 )
INSERT INTO [Table_Booking] ([TableBookingId],[BookingNr],[TableNr], GuestOnTable) VALUES (/* TableBookingId - INT */ 3, /* BookingNr - INT */ 3,/* TableNr - INT */ 1, 4 )
GO
Simple test query
select Booking.BookingNr, [Booking].[Time_From], [Booking].[Time_TO], [Booking].[Guests], [Tables].TableNr ,
CASE WHEN [Tables].[Seats] -
( select sum(tbInner.[GuestOnTable]) from [Table_Booking] as tbInner
join [Booking] AS bInner on bInner.BookingNr = tbInner.BookingNr
where (NOT ( Booking.Time_From>= bInner.[Time_To] OR bInner.[Time_From] >= Booking.Time_To ) )
) < 0 THEN 'OverBooked' ELSE 'Ok' END AS TableStatus
from [Booking]
join [Table_Booking] on [Booking].[BookingNr] = [Table_Booking].[BookingNr]
join [Tables] on [Tables].[TableNr] = [Table_Booking].[TableNr]
Gives me: Bookingnr 1 = overbooked Booking 2 and 3 = Ok.
If i remove booking 3. I get the expected result. the problem is when 3 or more bookings share time on the same table.
I don't want to resort to something like doing a loop over all the possible times during the booking and checking if it's overbooked. The query is used frequently, maybe once a minute by all the users, and there can be a couple of hundreds of rows for a day. I can use either SQL or delphi dataset (but i'd rather do it in SQL)
Edit 1
It is a part of a larger stored proc that does all kind of other stuff, so it could be a function.
I would prefer that i would'nt have to deal with min intervals. Most customers using the product doesn't have this problem since they don't allow splittning a table. And i don't want the query to be significantly slower for them.