Reputation: 2588
I have a membership table with the colums ID, Start_date, End_date, Duration, Value
ID | Start_date | End_date | Duration | Value |
1 | 2012-08-12 |2012-09-12| 30 | 10 |
2 | 2011-05-22 |2013-05-22| 720 | 2000 |
and so on
I want to turn it into two colums, one which has the date, each day of the year, and the other which has the sum of all Value/duration of memberships on that day.
I eventually need to turn it into a per month value, giving me a clear picture of what revenues to expect in the future thanks to running memberships.
Right now I did something like
select
sum(if("2012-01-01" between start_date and end_date, total_value/duration, null)) as "2012-01-01",
sum(if("2012-01-02" between start_date and end_date, total_value/duration, null)) as "2012-01-02",
[...]
sum(if("2013-12-31" between start_date and end_date, total_value/duration, null)) as "2013-12-31"
from MembershipsTable
/* 0 rows affected, 1 rows found. Duration for 1 query: 3,666 sec. */
but I do not see how I could easily sum them up to give me a per-month value. I could just create a sum of the columns again, but would rather not have to type in novels of text
Run time is not an issue for the current format
I need an output of the shape
Month | Sum |
Jan 2012 |4500 |
Feb 2012 |4215,91 |
Where the sum is the sum of all memberships intersecting that period calculated by price per day*number of days the membership has in the month.
So if a membership starts on 12 Nov, Ends 11 Dec, has a duration of 30, value of 300, I want to add 300/30*daysInNov to month november, same for dec, giving me +190 for Nov, +110 for Dec I need a sum of all memberships in that way.
Does anyone have any idea?
Upvotes: 1
Views: 410
Reputation: 5191
This is a bit of an ugly hack, but I believe something like the below would work if I'm understanding your needs correctly.
First, create a tabled named month_days that has all the months with their start and end date. You would use this as a utility table to join against and calculate monthly totals.
month_days
start_date | last_date
2012-01-01 | 2012-01-31
2012-02-01 | 2012-02-29
Then, execute a join and calculation something like this:
select format(month_days.start_date, 'MMM yyyy') AS [Month],
sum(case when (memberships.start_date > month_days.start_date AND memberships.end_date < month_days.end_date)
then datediff(day, memberships.end_date, memberships.start_date) * (value/duration)
when (memberships.start_date between month_days.start_date and month_days.end_date)
then (datediff(day, month_days.end_date, memberships.start_date) + 1) * (value/duration)
when (memberships.end_date between month_days.start_date and month_days.end_date)
then datediff(day, memberships.end_date, month_days.start_date) * (value/duration)
else (datediff(day, month_days.end_date, month_days.start_date) + 1) * (value/duration)
end) total_value
from memberships
inner join month_days
on memberships.start_date < month_days.end_date
and memberships.end_date > month_days.start_date
group by month_days.start_date
order by month_days.start_date
There are many ways to create the month_days table that would achieve a similar effect.
You could probably also write a stored procedure to iterate through the months for each record, populate a temp table (or table variable) with the monthly sums, then return the contents of the temp table.
Upvotes: 2