I am working on an apartment rental website where companies have their accounts and can upload properties. I'm stuck with seasonal pricing implementation. Each property may have different rates in different periods of time during a year. I have the following tables:
objects
drop table if exists objects;
create table objects (
id bigint unsigned not null primary key
);
insert into objects values('1200');
insert into objects values('1201');
insert into objects values('1202');
insert into objects values('1203');
rates
drop table if exists rates;
create table rates
(
id serial,
obj_id_sys bigint unsigned not null,
season varchar(100),
start_date date references calendar(date_),
end_date date references calendar(date_),
rate float
);
insert into rates values ('', '1203', 'default', '0000-00-00', '0000-00-00', 75.00);
insert into rates values ('', '1203', 'Low', '2014-06-01', '2014-06-30', 100.00);
insert into rates values ('', '1203', 'High', '2014-07-01', '2014-07-30', 150.00);
insert into rates values ('', '1203', 'Peak', '2014-09-01', '2014-09-30', 200.00);
insert into rates values ('', '1202', 'default', '0000-00-00', '0000-00-00', 85.00);
insert into rates values ('', '1202', 'June', '2014-06-01', '2014-06-30', 75.00);
insert into rates values ('', '1202', 'July', '2014-07-01', '2014-07-30', 90.00);
insert into rates values ('', '1202', 'September', '2014-09-01', '2014-09-30', 105.00);
insert into rates values ('', '1201', 'default', '0000-00-00', '0000-00-00', 92.00);
insert into rates values ('', '1201', 'Low', '2014-06-01', '2014-07-15', 80.00);
insert into rates values ('', '1201', 'High', '2014-07-01', '2014-08-30', 88.00);
insert into rates values ('', '1201', 'Peak', '2014-09-01', '2014-09-30', 95.00);
insert into rates values ('', '1200', 'default', '0000-00-00', '0000-00-00', 92.00);
insert into rates values ('', '1200', 'Low', '2014-06-01', '2014-06-30', 80.00);
insert into rates values ('', '1200', 'High', '2014-07-01', '2014-08-1', 88.00);
insert into rates values ('', '1200', 'Peak', '2014-09-01', '2014-09-30', 95.00);
Properties information is kept in the objects table.
Values in obj_id_sys field in rates table correspond to id in objects.
I want to return objects with their rates for an arbitrary user-defined period, say 2014-07-01 — 2014-08-20.
If the booking period does not meet any of the seasonal prices, the 'default' season price should be used.
I am using a helper table calendar with all possible dates:
drop procedure fill_calendar;
delimiter $$
create procedure fill_calendar(start_date date, end_date date)
begin
declare date_ date;
set date_=start_date;
while date_ <= end_date do
insert into calendar values(date_);
set date_ = adddate(date_, interval 1 day);
end while;
end $$
delimiter ;
drop table if exists calendar;
create table calendar
(
date_ date primary key
);
call fill_calendar('2014-1-1', '2020-12-31');
The following query returns almost what I want, except for that the default rate is returned for every date, even when seasonal prices are available for that one resulting in having tho rates for dates which fall within a season: that one of the season and the default one.
select
coalesce(objects.id, r.obj_id_sys) as id,
calendar.date_ as date_,
r.season as season,
r.rate as amount
from calendar
LEFT OUTER JOIN rates AS r
on (calendar.date_ >= r.start_date and calendar.date_ <= r.end_date) or r.season='default'
JOIN objects
on objects.id = r.obj_id_sys
WHERE calendar.date_ between '2014-07-29' and '2014-08-3'
order by id, date_
;
How can I return default rates only for those dates for which no seasonal prices are available? So that each object has only one rate for one date and I just do a SUM(rate) and GROUP BY id at the end to get object id and total price.
Also, some properties are available only during the seasons specified in table rates. If the booking period falls outside of these, the property should not be returned. Is there a way to do all of it in a single query?
Edit: This approach is based on this post:Hotel Room Rates for different seasons
Edit 2 Perhaps it'll be better not to use a single 'default' row for a property at all, filling instead the date ranges table with missing ranges and make them 'default'. But this is another problem. I posted it here: How to find missing date ranges?