Home > Net >  Check Hall Availability using Date range and Time slot
Check Hall Availability using Date range and Time slot

Time:09-30

I have 2 tables Halls & Bookings with the following schema & sample data

CREATE TABLE Halls 
(
    id bigint PRIMARY KEY IDENTITY(1,1), 
    hallName varchar(255) NOT NULL,
    hallType varchar(255) NOT NULL, 
    numSeats int NOT NULL, 
    status varchar(255) NOT NULL
    combinedIds int,
)

INSERT INTO Halls 
VALUES 
    ('Hall 1', 'Normal', 500, 'active', NULL),
    ('Hall 2', 'VIP', 30, 'active', NULL),
    ('Hall 3', 'VVIP', 5, 'active', NULL),
    ('Hall 4', 'Normal', 60, 'active', 6),
    ('Hall 5', 'Normal', 80, 'active', 6),
    ('Hall 4 5', 'Normal', 140, 'active', NULL);
   
SELECT * FROM Halls;


CREATE TABLE Bookings 
(
    id bigint PRIMARY KEY IDENTITY(1,1), 
    custId int NOT NULL,
    hallId int NOT NULL, 
    beginDate NVarChar(100), 
    endDate NVarChar(100) NOT NULL,
    time varchar(100) NOT NULL, 
    status varchar(100) NOT NULL
)

INSERT INTO Bookings 
VALUES 
  (1, 1, '2022-09-28', '2022-09-28', 'morning', 'confirmed'),
  (6, 4, '2022-09-28', '2022-09-29', 'evening', 'cancelled'),
  (4, 3, '2022-09-28', '2022-09-28', 'full time', 'pending'),
  (4, 6, '2022-09-28', '2022-09-28', 'morning', 'pending'),
  (9, 4, '2022-09-28', '2022-09-30', 'after noon', 'confirmed');

SELECT * FROM bookings;

Booking time slots are : "morning", "after noon", "evening" & "full time"

I have the above 2 tables and I want to validate incoming Bookings if an overlapping Bookings exist

in short, I want to check if any overlapping Bookings with status!='cancelled' exits for the date range(beginDate, endDate) & time slot before inserting

if we take in the above booking table with its sample data

  • Hall 1 should be available in 'after noon' & 'evening' time slots only

  • Hall 2 should be available in any time slot since it isn't ('morning', 'after noon', 'evening' OR 'full time')

  • Hall 3 should not be available at all since it's booked full time

  • Hall 4 should be available in morning & evening time slots

    NOTE: Evening is booked but cancelled, which means it's available to book again

  • Hall 5 should be available in any time slot('morning', 'after noon', 'evening' OR 'full time')

  • Hall 6 should be available in morning & evening time slots

    NOTE: Hall 6 is actually a combination of Halls 4 & 5 which means in any given time slots & date ranges for which one or both of them is Booked, Hall 6 should automatically be unavailable/booked

Here are some of my trials so far, without taking Hall 6 scenario into consideration

DECLARE @hallId int = 1;
DECLARE @beginDate NVarChar(50) = '2022-09-28';
DECLARE @endDate NVarChar(50) = '2022-09-29';
DECLARE @time NVarChar(50) = 'full time';

SELECT * 
FROM Bookings b 
WHERE b.hallId = @hallId  
  AND b.status != 'cancelled' 
  AND beginDate <= @endDate 
  AND endDate >= @beginDate
  AND b.time IN (@time, 'full time')

This query returns nothing which means it's available to book Hall 1 on 2022-09-28/29 in full time time slot, but then check the Bookings table, 'Hall 1' is actually booked on 2022-09-28 morning

AND If I put in the time slots for the time column as below

DECLARE @hallId int = 1;
DECLARE @beginDate NVarChar(50) = '2022-09-28';
DECLARE @endDate NVarChar(50) = '2022-09-29'; 
DECLARE @time NVarChar(50) = 'full time';

SELECT * 
FROM Bookings b 
WHERE b.hallId = @hallId  
  AND b.status != 'cancelled' 
  AND beginDate <= @endDate 
  AND endDate >= @beginDate
  AND b.time IN ('morning', 'after noon', 'evening', 'full time')

for any Hall that has an overlapping beginDate or endDate will be considered as booked regardless of time slot

I want something like this

CREATE PROCEDURE spBookings
    @id bigInt, 
    @hallId int, 
    @custId int,
    @beginDate NVarChar(50), 
    @endDate NVarChar(50), 
    @time NVarChar(50),
    @status NVarChar(50), 
    @msg NVarChar(200) OUT
AS
    IF EXISTS (SELECT * FROM Bookings b 
               WHERE b.hallId = @hallId  
                 AND b.status != 'cancelled' 
                 AND beginDate <= @endDate 
                 AND endDate >= @beginDate 
                 AND b.time IN (@time, 'full time'))
    BEGIN
        SET @msg = 'info|That date or time slot is booked, select a 
          different one'
    END
    ELSE
    BEGIN
        INSERT INTO Bookings (custId, hallId, beginDate, endDate, time, status)
        VALUES (@custId, @hallId, @beginDate, @endDate, @time, @status)

        SET @msg = 'success|Booking success'
    END

Here is a db-fiddle with the tables, their schema, sample data plus some more commented details

I posted this question here which was about Halls Availability report before and got advised to Normalize the Halls table for composite halls (hall 6).

I really appreciate whatever the best possible solution to get around this.

CodePudding user response:

The solution is similar to your earlier Check Hall Booking status question.

The basic concept is to find any matches of your input against the booking information. Not directly from the Bookings table but the exploded, taking into consideration of the combinedIds. And for this case, you are only interested in the unavailable status, you can filter out the cancelled

   select b.hallId, b.time, beginDate, endDate
   from   Bookings b
   where  b.status not in ('cancelled')

   union all

   select hallId = h.combinedIds, b.time, b.beginDate, b.endDate
   from   Bookings b
         inner join Halls h on b.hallId = h.id
   where  b.status not in ('cancelled')
   and    h.combinedIds is not null

   union all

   select hallId = h.id, b.time, b.beginDate, b.endDate
   from   Bookings b
          inner join Halls h on b.hallId = h.combinedIds
   and    h.combinedIds is not null
   where  h.combinedIds is not null

Next you need to translate full time into 3 rows of morning, afternoon (by the way it is spelled without a space in between), evening. You can do that with following query

select time = 'morning' where @time in ('morning', 'full time')
union all
select time = 'afternoon' where @time in ('afternoon', 'full time')
union all
select time = 'evening' where @time in ('evening', 'full time')

The above query are actually solution from your previous question.

Putting all together

SELECT *
FROM   
(
    select time = 'morning' where @time in ('morning', 'full time')
    union all
    select time = 'afternoon' where @time in ('afternoon', 'full time')
    union all
    select time = 'evening' where @time in ('evening', 'full time')
) t
INNER JOIN
(
       select b.hallId, b.time, beginDate, endDate
       from   Bookings b
       where  b.status not in ('cancelled')
  
       union all
  
       select hallId = h.combinedIds, b.time, b.beginDate, b.endDate
       from   Bookings b
             inner join Halls h on b.hallId = h.id
       where  b.status not in ('cancelled')
       and    h.combinedIds is not null
  
       union all
  
       select hallId = h.id, b.time, b.beginDate, b.endDate
       from   Bookings b
              inner join Halls h on b.hallId = h.combinedIds
       and    h.combinedIds is not null
       where  h.combinedIds is not null
) b ON t.time = b.time
WHERE b.hallId    = @hallId
AND   @beginDate <= b.endDate
AND   @endDate   >= b.beginDate

And incorporate that into your stored procedure

IF   EXISTS
     (
         < above query>
     )
BEGIN
   -- not available
END
ELSE
BEGIN
    -- insert into Bookings table
END

db<>fiddle demo

Side Note :

Please use proper data type example for begin/end Date use DATE instead of nvarchar

  • Related