Checking for Overlap in Date Ranges

  • I have made an application for hotels that contains a table called ReservationRooms containing, inter alia, ResNo, ResDate, ResRoom, CheckinDate, CheckoutDate, and Status. When a new reservation is being entered, the application loops through existing reservations for each room and uses this formula ascertain whether a room is vacant or not for the stated date range:

    SELECT COUNT(RESNO)

    FROM RESERVATIONROOMS

    WHERE RESROOM = ROOMNO

    AND

    (

    DATEIN BETWEEN CHECKINDATE AND (CHECKOUTDATE - 1)

    --CHECK ONLY UNTIL THE PREVIOUS DAY

    --MAY BE CHECKED IN ONCE IT HAS BEEN CHECKED OUT

    OR

    DATEOUT BETWEEN (CHECKINDATE + 1) AND CHECKOUTDATE

    --CHECK ONLY FROM AFTER CHECKIN

    --MAY BE CHECKED OUT THE SAME DAY AS IT IS CHECKED IN

    )

    This formula served me well for a long time, although I had not thought through all the possible

    situations when it will yield wrong results. It so happened that if a new reservation "straddled" an existing reservation's checkin and checkout dates, the respective room would show up as vacant, e.g.: if Room 112 is booked from 24Dec2008 to 26Dec2008 and a clerk checks for rooms vacant from 20Dec2008 to 31Dec2008 the formula would work thus:

    [Code]IF 20Dec2008 BETWEEN 24DEC2008 AND 25DEC2008 --FALSE

    OR 31DEC2008 BETWEEN 25DEC2008 AND 26DEC2008 --FALSE [/Code]

    so I extended the formula by adding a reverse test as follows:

    SELECT COUNT(RESNO)

    FROM RESERVATIONROOMS

    WHERE RESROOM = ROOMNO

    AND

    (

    (

    DATEIN BETWEEN CHECKINDATE AND (CHECKOUTDATE - 1) --CHECK ONLY UNTIL THE PENULTIMATE DAY AS A ROOM

    OR --MAY BE CHECKED IN ONCE IT HAS BEEN CHECKED OUT

    DATEOUT BETWEEN (CHECKINDATE + 1) AND CHECKOUTDATE --CHECK ONLY FROM THE DATE AFTER CHECKIN AS A ROOM

    ) --MAY BE CHECKED OUT THE SAME DAY AS IT IS CHECKED IN

    OR

    (

    CHECKINDATE BETWEEN DATEIN AND (DATEOUT - 1) --CHECK ONLY UNTIL THE PENULTIMATE DAY AS A ROOM

    OR --MAY BE CHECKED IN ONCE IT HAS BEEN CHECKED OUT

    CHECKOUTDATE BETWEEN (DATEIN + 1) AND DATEOUT --CHECK ONLY FROM THE DATE AFTER CHECKIN AS A ROOM

    )

    )

    This traps all situations I can think of right now, although I will welcome any tips on foolproofing it.

    However, the reason I am posting here is that having read a lot about how tally tables help improve date-processing queries, I would like to know how I can incorporate a tally table to enhance this query. I am certain that only applying a tally table will give me the number of days in a given date range that are already taken by existing bookings, for example, the above instance is passing a date range of 11 days to check for vacancy whilst the room has been booked for only 2 days out of the 11.


    Regards,

    goodguy

    Experience is a bad teacher whose exams precede its lessons

  • If you are really "looping" then a Tally table can help you to get rid of that Loop. If so, then please post the whole SQL procedure, not just this fragment.

    [font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
    Proactive Performance Solutions, Inc.
    [/font]
    [font="Verdana"] "Performance is our middle name."[/font]

  • That said, here is how I would do something like this:

    Select Room

    From Rooms R

    WHERE Not Exists (Select * from ReservationRooms RR

    Where R.Room = RR.ResRoom

    And CHECKINDATE < @DATEOUT

    And CHECKOUT >= @DATEIN

    )

    I included some of the outer query, because it is necessary to understand the logic of the inner query.

    [font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
    Proactive Performance Solutions, Inc.
    [/font]
    [font="Verdana"] "Performance is our middle name."[/font]

  • Hi,

    Will this be useful or this also fails anywhere/

    select count(RESNO) from RESERVATIONROOMS

    where checkin not between Datein and Dateout and checkout not between DateIn and DateOut

    Regards,

    Rajesh

  • Hi, we do this all the time.. so I think you can steal my logic.. it's simple enough to not need a tally table?

    SELECT COUNT(RESNO)

    FROM RESERVATIONROOMS

    WHERE RESROOM = ROOMNO

    AND (DATEIN <= (CHECKOUTDATE - 1)

    AND DATEOUT >= (CHECKINDATE + 1))

    Examples of why it should work:

    -- EXAMPLE FORMAT

    DATEIN <= CHECKOUTDATE - 1

    DATEOUT >= CHECKINDATE + 1

    -- Overlap example.. does not allow booking

    20081220 <= 20081225 - 1 -- TRUE

    20081231 >= 20081224 + 1 -- TRUE

    -- Booking prior to existing.. allows booking

    20081220 <= 20081225 - 1 -- TRUE

    20081222 >= 20081224 + 1 -- FALSE

    -- Booking after existing.. allows booking

    20081225 <= 20081225 - 1 -- FALSE

    20081228 >= 20081224 + 1 -- TRUE

  • raja_saminathan (5/28/2008)[hrWill this be useful or this also fails anywhere/

    select count(RESNO) from RESERVATIONROOMS

    where checkin not between Datein and Dateout and checkout not between DateIn and DateOut

    Rajesh, sorry, this fails to catch cases where CheckIn-CheckOut spans (surronds) DateIn-DateOut.

    [font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
    Proactive Performance Solutions, Inc.
    [/font]
    [font="Verdana"] "Performance is our middle name."[/font]

  • janine: Except for the +/-1's this is the same logic as mine.

    [font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
    Proactive Performance Solutions, Inc.
    [/font]
    [font="Verdana"] "Performance is our middle name."[/font]

  • FORMULA#1 - BARRY

    Select Room

    From Rooms R

    WHERE Not Exists

    (

    Select * from ReservationRooms RR

    Where R.Room = RR.ResRoom

    And CHECKINDATE < @DATEOUT

    And CHECKOUT >= @DATEIN

    )

    FORMULA#2 - JANINE

    SELECT COUNT(RESNO)

    FROM RESERVATIONROOMS

    WHERE RESROOM = ROOMNO

    AND (@DATEIN <= (CHECKOUTDATE - 1)

    AND @DATEOUT >= (CHECKINDATE + 1))

    FORMULA#3 - GOODGUY

    SELECT COUNT(RESNO)

    FROM RESERVATIONROOMS

    WHERE RESROOM = ROOMNO

    AND

    (

    (

    @DATEIN BETWEEN CHECKINDATE AND (CHECKOUTDATE - 1)

    OR

    @DATEOUT BETWEEN (CHECKINDATE + 1) AND CHECKOUTDATE

    )

    OR

    (

    CHECKINDATE BETWEEN @DATEIN AND (@DATEOUT - 1)

    OR

    CHECKOUTDATE BETWEEN (@DATEIN + 1) AND @DATEOUT

    )

    )

    TEST RESULTS

    CHECKINDATE CHECKOUTDATE @DATEIN @DATEOUT ACTUAL F#1 F#2 F#3

    20DEC2008 01JAN2009 24DEC2008 26DEC2008 Y Y Y Y

    20DEC2008 01JAN2009 21DEC2008 22DEC2008 Y Y Y Y

    24DEC2008 26DEC2008 20DEC2008 01JAN2009 Y Y Y Y

    21DEC2008 22DEC2008 20DEC2008 01JAN2009 Y Y Y Y

    20DEC2008 22JAN2009 18DEC2008 21DEC2008 Y Y Y Y

    18DEC2008 21DEC2008 20DEC2008 22JAN2009 Y Y Y Y

    18DEC2008 21DEC2008 21DEC2008 24JAN2009 N Y* N N

    21DEC2008 24JAN2009 18DEC2008 21DEC2008 N N N N

    20DEC2008 24JAN2009 18DEC2008 21DEC2008 Y Y N* Y


    Regards,

    goodguy

    Experience is a bad teacher whose exams precede its lessons

  • Goodguy, I know my code fails on one of those tests but I kept the date manipulation as per original logic. I don't know why but seems he is intentionally allowing the checkin date to be as it is.

    To fix the error in your example (assuming OP's logic is also in error) simply:

    FORMULA#2 - JANINE

    SELECT COUNT(RESNO)

    FROM RESERVATIONROOMS

    WHERE RESROOM = ROOMNO

    AND (@DATEIN <= (CHECKOUTDATE - 1)

    AND @DATEOUT >= (CHECKINDATE))

    .. though this "fails" on anotehr test instead.

    I think at this point the question should be; what is the business logic? Can you have a person check out and another person check in the same day? etc.

  • [Quote]Goodguy, I know my code fails on one of those tests but I kept the date manipulation as per original logic. I don't know why but seems he is intentionally allowing the checkin date to be as it is.

    To fix the error in your example (assuming OP's logic is also in error) simply:

    FORMULA#2 - JANINE

    SELECT COUNT(RESNO)

    FROM RESERVATIONROOMS

    WHERE RESROOM = ROOMNO

    AND (@DATEIN <= (CHECKOUTDATE - 1)

    AND @DATEOUT >= (CHECKINDATE))

    .. though this "fails" on another test instead. I think at this point the question should be what is the business logic? Can a person check out and another person check in the same day? etc.[/Quote]

    Yes, in hotels, departing guests have to check out by a fixed hour every morning, between 8am and 11am. New arrivals are checked in about an hour later in order to allow for rooms to be cleaned etc.

    I am Goodguy and I am the OP. My logic is not in error, as I have demonstrated in the test results for the three formulas, mine consistently returns correct results.

    I am just looking for a way to do this

    (1) more efficiently

    (2) get a count of the number of days common to the two date ranges.


    Regards,

    goodguy

    Experience is a bad teacher whose exams precede its lessons

  • It's simple enough to correct mine, given this clarification:

    Select Room

    From Rooms R

    WHERE Not Exists (Select * from ReservationRooms RR

    Where R.Room = RR.ResRoom

    And CHECKINDATE < @DATEOUT

    And CHECKOUT > @DATEIN

    )

    Janine's can also be corrected if you really want it in the COUNT(*) form:

    SELECT COUNT(RESNO)

    FROM RESERVATIONROOMS

    WHERE RESROOM = ROOMNO

    AND @DATEIN < CHECKOUTDATE

    AND @DATEOUT > CHECKINDATE

    Both of these should be significantly faster and they have the additional advantage of being SARGE-able, which means that they can use indexes for searching.

    [font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
    Proactive Performance Solutions, Inc.
    [/font]
    [font="Verdana"] "Performance is our middle name."[/font]

  • Thanks, all.


    Regards,

    goodguy

    Experience is a bad teacher whose exams precede its lessons

  • This example is exactly what I'm working with for apartment availabilty search.

    So, basically I just need to extend the code so that it returns all the properties that are available between those two dates. Just as with hotels, departure date can equal arrival date. But instead of complicating the code, my booking are nights so you book the night of the 12th and someone else can book the night of the 13th, so there should be no overlapping dates.

    My existing SP returns a list of properties from the RentalProperty table from a query

    I then want to use the results from this to check each one in the list against the dates.

    Tables:

    RentalProperty

    RentalPropertyBookingCalendar

    linked on the RentalPropertyID int field

    these are the dates I will send in to check against:

    @QstartDate

    @QendDate

    I ended up with this, but doesn't work:

    SELECT *

    FROM dbo.RentalProperty R

    WHERE (AgentID = 93) AND (NOT EXISTS

    (SELECT *

    FROM RentalPropertyBookingCalendar RR

    WHERE R.RentalPropertyID = RR.RentalPropertyID AND ((FromDate 12 / 06 / 2009) OR

    (FromDate > 15 / 06 / 2009 AND ToDate < 12 / 06 / 2009))))

  • richard (4/21/2009)


    I ended up with this, but doesn't work:

    You'll have to give us more information than that. What would help us are table definitions (as CREATEs), sample data (as INSERTs), what results you are getting and what results you want.

    [font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
    Proactive Performance Solutions, Inc.
    [/font]
    [font="Verdana"] "Performance is our middle name."[/font]

  • Thanks, I have solved it now.

    I used and modified the code from this post and it works a treat.

    ....AND

    WHERE (NOT EXISTS

    (SELECT *

    FROM RentalPropertyBookingCalendar RR

    WHERE R.RentalPropertyID = RR.RentalPropertyID AND ((FromDate @QStartDate) OR

    (FromDate > @QEndDate AND ToDate < @QStartDate))))

Viewing 15 posts - 1 through 15 (of 26 total)

You must be logged in to reply to this topic. Login to reply