Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find booking overlaps to check dates availability

Tags:

sql

mysql

i asking your help to write an query for checking the availability of an room inside MySql. Currently i have this kind of table:

 ROOM |    FROM    |     TO
 -----------------------------
  101 | 2014-08-09 | 2014-08-14 
  102 | 2014-08-09 | 2014-08-14 
   ...           ...        ...

So i have the room 101 booked from 09-08-2014 to 14-08-2014, my query to check availability is look like =

SELECT order_id FROM booking 
WHERE `ROOM` = '101' 
AND (`FROM` BETWEEN '2014-08-08' AND '2014-08-20') 
AND (`TO` BETWEEN '2014-08-08' AND '2014-08-20')

In the above example i will check the availability in the dates between

   What i trying to archive is this
Order  --------09++++++++++13--------------
Check1 -----08+++++++++++++++++++++++++17-- Not availble
Check2 -----------------12+++++++++++++17-- Not availble
Check3 -----------10----------------------- Not availble
Check4 -----------10+11-------------------- Not availble
Check5 -----------------------14+++++++17-- Available
Check6 --07++++09-------------------------- Not availble
Check7 --------------------------15-------- Availble


SCALE  6-07-08-09-10-11-12-13-14-15-16-17-18-19...

I must check if the room is available. So if i get some result out of that query that means that the room is already booked... if i get nothing just the opposite...

like image 823
KeySee Avatar asked Aug 28 '14 13:08

KeySee


2 Answers

First, let's generalize an algorithm for how to check for an overlap between intervals [a,b] and [c,d]. Note the square braces on those intervals, which means an inclusive interval. We can use this logic to check for an interval overlap:

a <= d and b >= c

If that condition is true, then we have an overlap.

So to apply this algorithm to SQL, we could do something like this:

a = 2014-08-08
b = 2014-08-20
c = FROM
d = TO
SELECT order_id FROM booking 
WHERE NOT EXISTS (
     SELECT * FROM booking
       WHERE ROOM = '101'
         AND '2014-08-08' <= `TO`
         AND '2014-08-20' >= `FROM`
 )
 AND ROOM = '101'

The other problem with your approach is that you are checking to see if a room is available, and the assumption here is that if the room is available, then you will book it with another SQL statement. This is a problematic approach, because there is the possibility that you could double book a room. Consider the possibility that two processes check for room availability at the same (or close to the same) time. Or another example would be if this code were part of a transaction that hadn't been committed yet. The other process wouldn't see your committed result, and thus, would double book the room.

To remedy this flawed approach, we need to lock the room row before we check for its availability. Assuming you have some other table called ROOM, you could lock the row using a 'FOR UPDATE' statement:

SELECT * FROM `ROOM` WHERE ROOM = '101' FOR UPDATE

The "FOR UPDATE" will lock that room row, which will prevent another process from checking that room for availability until your transaction is finished. After you lock the row, you could run your overlap check. Thus, you eliminate the double booking problem.

You can read more about 'FOR UPDATE' here.

like image 120
dcp Avatar answered Sep 30 '22 17:09

dcp


If you want to check whether room is available for the whole period, look for existing bookings that overlap with period in question:

SELECT order_id FROM booking 
WHERE `ROOM` = '101' 
 AND `FROM` <= '2014-08-20' 
 AND `TO` >= 2014-08-08' 

If query returns rows, you have a reservation conflict and room is not available.

like image 26
Bulat Avatar answered Sep 30 '22 18:09

Bulat