Query: Calculate average price of stay depending on dates
Hello all,
I need to create a query for house search, that would match in database user entered data: date when they want to move in and leave, number of people they have in group and price per night.
Lets say user searched for house:
dates: from 2011-01-15 to 2011-03-01 (see on picture period A1C1), for 3 people, and he is willing to spend from $90 to $125 dollars per night.
This is my manual calculations for this search:
- dates available in database
- total number of dates user wants to stay is: 44 days
- price for the first period 2011-01-15 to 2011-01-25 is 10 days * $100 = $1000
- price for the second period 2011-01-25 to 2011-02-14 is 20 days * $120 = $2400
- price for the third period 2011-02-14 to 2011-03-01 is 14 days * $140 = $1960
- total average price per night = 1000 + 2400 + 1960 / 44 = $121.8
- price and number of people matches user input, so we display this开发者_如何转开发 house
If you merge dates and calculate average price per night for the given period, search script should match array of data provided above.
My question is this: How my query should look like to calculate quickly if user data matches records in database.
I was thinking about using SQL DATEDIFF function and then multiply by price ... etc but it looks to me pretty complex.
I will appreciate any advice.
Thank you
UPDATE
Here is my database schema:
Table "apt_search_periods" which stores all merged dates (continuous dates from availability table)
+-----------+------------+------------+-----------+--------------+--------+
| period_id | start_date | end_date | rental_id | nb_of_people | merged |
+-----------+------------+------------+-----------+--------------+--------+
| 21 | 2011-03-31 | 2012-03-31 | 548 | 4 | y |
+-----------+------------+------------+-----------+--------------+--------+
Table "apt_search_periods_avail" linking merged dates with availability table
+----+-----------+-----------------+
| id | period_id | availability_id |
+----+-----------+-----------------+
| 21 | 21 | 20953 |
| 22 | 21 | 20952 |
| 23 | 21 | 4033 |
+----+-----------+-----------------+
Table "availability" with expanded dates and prices
+-------+-----------+------------+------------+--------------+--------------+
| id | rental_id | start_date | end_date | nb_of_people | rent_per_day |
+-------+-----------+------------+------------+--------------+--------------+
| 20952 | 548 | 2011-03-31 | 2011-07-01 | 4 | 575 |
| 4033 | 548 | 2011-07-01 | 2011-09-01 | 4 | 680 |
| 20953 | 548 | 2011-09-01 | 2012-03-31 | 4 | 575 |
+-------+-----------+------------+------------+--------------+--------------+
Following should get you started.
Note that the only difference is that the third period comprises 15 days io 14 according to DATEDIFF.
SQL Statement
;WITH q AS (
/* Kick of with the record where startdate < input < enddate */
SELECT date_start
, date_end
FROM @HouseSearch
WHERE date_start <= @date_start
AND date_end >= @date_start
AND nb_people >= @nb_people -- Only when number of people is adequate
UNION ALL
SELECT q.date_start
, hs.date_end
FROM q
INNER JOIN @HouseSearch hs ON hs.date_start = q.date_end
WHERE nb_people >= @nb_people -- Only when number of people is adequate
)
SELECT *
FROM (
-- Only return result if sequence exists between date range
SELECT date_start = MIN(date_start)
, date_end = MAX(date_end)
FROM q
WHERE date_end >= @date_end
) datetimerange
-- Calculate the average price
CROSS APPLY (
SELECT [AveragePrice] = SUM(price / DATEDIFF(dd, @date_start, @date_end))
FROM (
-- Price for all records where date_end <= @date_end
SELECT [price] =
CASE WHEN @date_start < date_start
THEN DATEDIFF(dd, date_start, date_end) * price
ELSE DATEDIFF(dd, @date_start, date_end) * price
END
FROM @HouseSearch
WHERE @date_end > date_end
UNION ALL
-- Price of remaining records where date_end >= @date_end
SELECT DATEDIFF(dd, date_start, @date_end) * price
FROM @HouseSearch
WHERE @date_end between date_start AND date_end
) prices
) price
WHERE date_start IS NOT NULL
Test data
DECLARE @HouseSearch TABLE (
date_start DATE
, date_end DATE
, nb_people INTEGER
, price FLOAT
)
INSERT INTO @HouseSearch VALUES
('2011-01-01', '2011-01-25', 4, 100)
, ('2011-01-25', '2011-02-14', 3, 120)
, ('2011-02-14', '2011-03-12', 3, 140)
, ('2011-03-12', '2011-04-10', 3, 100)
DECLARE @date_start DATE = '2011-01-15'
DECLARE @date_end DATE = '2011-03-01'
DECLARE @nb_people INTEGER = 3
DECLARE @price_low FLOAT = 90
DECLARE @price_high FLOAT = 15
精彩评论