I'm looking for some design advice on a hotel room like booking system. I've read a lot of stuff on this so far and I've got a query which returns a list of rooms which are available for a certain date range.
My search currently only returns rooms which are available for the entire booking period the user is searching for. I'd like to expand this so I can fulfill the request with multiple rooms. I.e. User searches for a date range and Room 1 is available for the first 2 days, then they would need to be transferred to Room 2 for the last 2 days.
I currently do my availability lookup using the following query;
Dim available = From k In rooms _ Group Join r In db.Reservations.Where(Function(fx) (fx.DateIn >= Date_From And fx.DateIn < Date_To) Or (fx.DateOut > Date_From And fx.DateOut <= Date_To)) On k Equals r.Room Into Group _ From r In Group.DefaultIfEmpty Where r Is Nothing Select k
How can I alter my design or expand on the current design to allow multiple rooms per booking? I'm a bit stumped!
Gracias de antemano!
preguntado el 10 de marzo de 12 a las 15:03
What if you changed your initial query to simply search for rooms that are available on the person's arrival date, sorted by the longest amount of time each room is open for in descending order? If that amount of time is enough to cover the person's stay, then you're done. If it isn't, recurse. Query again to search for rooms that are available on the date the first room becomes unavailable, again sorted by the longest amount of time each room is open for in descending order. Continue until you've either hit a date that has no available rooms or you've found enough rooms to cover the person's stay.
For example, let's say you have someone who wants to book a reservation from 1/1 - 1/10 and there are three rooms with the following availability:
- Room 1: Available from 1/1 to 1/9
- Room 2: Available from 1/1 to 1/5
- Room 3: Available from 1/5 to 1/10
Your first query would be to see which rooms are available on 1/1, which would return rooms 1 and 2. However, since you're sorting by the longest amount of time each room is open for, your top result would be room 1. Your second query would be to see which rooms are available on 1/10 (the first date room 1 becomes unavailable), which would return room 3. You'd then determine that room 3 is open long enough to satisfy the person's reservation and you're done.
Okay so in SQL:
Table room_booking is like
roomid INT (FK to room table), from DATE, to DATE
so deciding IF there is enough room would be the question of the opposite: In the timeframe of the visit, is there a situation where there is NO ROOM available? So we split the frame in days (because rooms are not rented by the hour in your case, or are they?) and select that.
So you need to determinate every day for the visit PRIOR to the selection and then calculate how many free rooms you have for each of that days.
SELECT count(roomid) - (SELECT count(id) from room) as numOfFreeRooms FROM room_booking WHERE '2012-03-10' >= from AND '2010-03-10' <= to
If any of the rows returns '0' (means all rooms are booked on that day) then you cannot fulfill your customers request.
If performance is relevant than this can be improved, but is more complicated then.
So my second solution, its (as said in the comments to the first one) quite complicated but I think its quite efficient as well.
I will not post code but rather the overall concept, if you are interested in specific details I'll see what I can do.
Problem: We create a abstraction where every room on every day is either available or blocked. We are interested in the available rooms in the time the guest wants to visit. We want to select the combination of rooms that need the least relocations of the guest.
Abstract: We create a two dimensional matrix of room/day combinations where every day is represented by a power of two (the DAYVALUE). A room thats available has the corresponding DAYVALUE. A room thats blocked as a value of SERO. So if we sum all DAYS for a ROOM we can determinate what COMBINATION of ROOMS fulfills the full time.
More specific: after we get the SUM of all VALUES for a ROOM we can use the binary OR function to decide if a given combination of rooms fullfills the complete stay by comparing the result of the OR operation with the SUM of values for all DAYS.
Note that the DAYVALUE is not stored in the dayTable. It is calculated for every request (2^(STARTDAY-DAY))
1) You need to create a table that contains all DAYS. It has exactly ONE column that contains a date (no time, no timezone only the day). I would recommend it to contain ALL days from now until in a hundred years. (so you will have to populate it only once). (Note: This solves the problem that you cannot select every day once in a SQL Query)
2) You create a VIEW that produces an output like this:
DAY ; DAYVALUE ; ROOM1 ; ROOM2; ROOM3 ; ROOM4 ; ... ; ROOMn 20120313 ; 1 ; 0 ; 0; 1 ; 1 ; ... ; 20120314 ; 2 ; 2 ; 0; 2 ; 2 ; ... ; 20120315 ; 4 ; 4 ; 0; 0 ; 4 ; ... ; 20120316 ; 8 ; 8 ; 0; 0 ; 0 ; ... ; 20120317 ; 16 ; 16 ; 16; 16 ; 0 ; ... ;
3) Produce a SUM of this.
DAYVALUE ; ROOM1 ; ROOM2; ROOM3 ; ROOM4 ; ... ; ROOMn 31 ; 30 ; 16; 19 ; 7 ; ... ;
4) see if any single of the room values matches the sum of the DAYVALUE (and therefore is available all the time)
5) if 4 did not succeed create an OR value of every two of the results and compare it to the SUM of the DAYVALUE
ROOM1 OR ROOM2 = 30 <> 31 ROOM1 OR ROOM3 = 31 == 31. This is a valid match of rooms.
6) If none matched for two rooms you have to proceed this for 3 ROOMS and so on.
Using this procedure always produces the correct set of rooms that are available in the time of the visit and if you construct your database in the correct way (or have sufficiently low amount on rooms) the query should complete in a acceptable time.
Have fun (I had!)