Reputation: 40291
I have a table the stores vehicles reservations for each record I have dateFrom
"the reservation start date" and a dateTo
"the reservation end date"
I am trying to write a query to calculate the total of day each vehicles was booked and also the total of revenue each vehicles generates.
The business rule are are the following
dateFrom
and dateTo
are in the same day then that is considered 1 days2013-05-25
to 2013-06-06
then then 7 days go to the month of may and 5 days go to the month of june here is a break down of this logic2013-05-25 - 2013-05-26 (May) 2013-05-26 - 2013-05-27 (May) 2013-05-27 - 2013-05-28 (May) 2013-05-28 - 2013-05-29 (May) 2013-05-29 - 2013-05-30 (May) 2013-05-30 - 2013-05-31 (May) 2013-05-31 - 2013-06-01 (**May**) 2013-06-01 - 2013-06-02 (June) 2013-06-02 - 2013-06-02 (June) 2013-06-03 - 2013-06-02 (June) 2013-06-04 - 2013-06-02 (June) 2013-06-05 - 2013-06-02 (June)
This is an example on how the calculation should work.
For the revenue I am suppose to calculate the average daily rent by dividing the total revenue by the total rented days then multiplying the daily average by the total day that fits this range
This is my current query but it is not calculating the today days correctly.
so in the above example if we assume that the total revenue for the whole reservation is $1500
then the average daily rent is $1500/12 = $125
so since the range that we are calculating is "2013-06-01 00:00:00"
to "2013-06-16 23:59:59"
, the this vehicle should display total days are 5 and total revenue is $625.
More, if the range was 2013-05-01 00:00:00
to 2013-05-31 23:59:59
then the same vehicle will have total of 7 days and total revenue of $875
The following is my current query in where I am trying to calculate the differences.
SELECT rs.vehicle_id,
ROUND(SUM(
CASE
WHEN (rs.dateFrom BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59")
AND (rs.dateTo BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59")
THEN (rs.totalRent + rs.totalTax)
WHEN rs.dateTo BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59"
AND rs.dateFrom < "2013-06-01 00:00:00"
THEN ( ( (rs.totalRent + rs.totalTax) / CASE WHEN DATEDIFF( rs.dateTo,rs.dateFrom) = 0 THEN 1 ELSE DATEDIFF( rs.dateTo,rs.dateFrom) END) * (DATEDIFF(rs.dateTo, "2013-06-01 00:00:00")) )
WHEN rs.dateFrom BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59"
AND rs.dateTo > "2013-06-16 23:59:59"
THEN ( ( (rs.totalRent + rs.totalTax) / CASE WHEN DATEDIFF( rs.dateTo,rs.dateFrom) = 0 THEN 1 ELSE DATEDIFF( rs.dateTo,rs.dateFrom) END) * (DATEDIFF( "2013-06-16 23:59:59",rs.dateFrom)+1) )
WHEN rs.dateFrom < "2013-06-01 00:00:00" AND rs.dateTo > "2013-06-16 23:59:59"
THEN ( ( (rs.totalRent + rs.totalTax) / CASE WHEN DATEDIFF( rs.dateTo,rs.dateFrom) = 0 THEN 1 ELSE DATEDIFF( rs.dateTo,rs.dateFrom) END) * (DATEDIFF( "2013-06-16 23:59:59", "2013-06-01 00:00:00") +1) )
ELSE 0 END
)) AS income,
SUM(
CASE
WHEN (rs.dateFrom BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59")
AND (rs.dateTo BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59")
THEN CASE WHEN DATEDIFF( rs.dateTo,rs.dateFrom) = 0 THEN 1 ELSE DATEDIFF( rs.dateTo,rs.dateFrom) END
WHEN rs.dateTo BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59"
AND rs.dateFrom < "2013-06-01 00:00:00"
THEN CASE WHEN DATEDIFF(rs.dateTo, "2013-06-01 00:00:00") = 0 THEN 1 ELSE (DATEDIFF(rs.dateTo, "2013-06-01 00:00:00")) END
WHEN rs.dateFrom BETWEEN "2013-06-01 00:00:00" AND "2013-06-16 23:59:59"
AND rs.dateTo > "2013-06-16 23:59:59"
THEN CASE WHEN DATEDIFF( "2013-06-16 23:59:59",rs.dateFrom) = 0 THEN 1 ELSE (DATEDIFF( "2013-06-16 23:59:59",rs.dateFrom)) END
WHEN rs.dateFrom < "2013-06-01 00:00:00" AND rs.dateTo > "2013-06-16 23:59:59"
THEN DATEDIFF( "2013-06-16 23:59:59", "2013-06-01 00:00:00")+1
ELSE 0 END
) AS days
FROM reservation AS rs
WHERE rs.reservationStatus IN (2,3)
GROUP BY rs.Vehicle_id
The problem is that the query is not calculating the total days correctly. Can somebody help me with this please?
The following is a sample of my code
http://sqlfiddle.com/#!2/f6cbc/3 for testing with data
Upvotes: 3
Views: 1277
Reputation: 7991
So I've taken a stab at it. Let's start with the code. The explanation comes later.
SELECT rs.vehicle_id,
round(sum(datediff(least(rs.dateTo, '2013-06-02 00:00:00'),
greatest(rs.dateFrom, '2013-05-31 00:00:00'))*(totalRent + totalTax)*datediff(least(rs.dateTo, '2013-06-02 00:00:00'),
greatest(rs.dateFrom, '2013-05-31 00:00:00'))/totalDays))
AS income,
sum(datediff(least(rs.dateTo, '2013-06-02 00:00:00'),
greatest(rs.dateFrom, '2013-05-31 00:00:00')))
AS days
FROM reservation rs
WHERE rs.dateFrom < '2013-06-02 00:00:00'
AND rs.dateTo > '2013-05-31 00:00:00'
GROUP BY rs.vehicle_id;
The most important thing that you have to think about is whether the date range is inclusive or exclusive. So, if you want the amount from 5/31 to 6/1, does this mean that you want to include revenue from 6/1 or does this mean that you are only looking for revenue on 5/31. This concept trips a lot of developers up. From your comments and posts, I'm assuming that you want the date range to be exclusive.
In the case I created, the window goes from 5/31 at 00:00:00 to 6/1 at 00:00. If you want it to be inclusive, you could end the window at 6/2 00:00:00.
The rest of the solution is just a little more elegant way of doing what you were already doing. You can look for a date window by seeing if the start date is less than the end of the date range and the end date is greater than the start of the date range.
Then you can calculate the actual amount of days in the window by looking at the maximum of the dateFrom and the windowStart, as well as the minimum of the dateTo and the windowEnd.
Upvotes: 1
Reputation: 1820
There is no overlap in intervals(i.e. for a car you have some logic to ensure that it is not reserved multiple times?
If you are looking for the entire history, you can certainly just sum up the invidual lengths of each reservation. Do you want some per-month breakdown?
SELECT SUM( TO_DAYS(dateTo)-TO_DAYS(dateFrom) +1 ) AS sum_days_reserved FROM table
Upvotes: 1