I have this Event
model
class Event < ActiveRecord::Base
attr_accessible :starts_at, :ends_at, :price
end
An Event
can be a single instant event:
Event.create(:starts_at => Date.today, :ends_at=>nil, :price => 10.0)
It can also span multiple days or months:
Event.create(:starts_at => Date.today, :ends_at => (Date.today + 2.months), :price => 20.0)
I want to break down the cost of events by months, so that cost for an instant event falls into the month it belongs to, naturally, and cost for an event that spans multiple months should be divided proportionally between those months.
Obviously this would be difficult to handle using SQL, but maybe someone has some advice on that?
What would be the most efficient way of calculating this aggregation?
Update:
Here is a clearly defined structure for the data on sqlfiddle: http://sqlfiddle.com/#!12/a532e/6
What I would want from this dataset is something like:
( (Date('2013-01-01'), 31.6), (Date('2013-02-01'), 8.4) )
SELECT event_id
,date_trunc('month', day)::date AS month
,sum(daily) AS price_this_month
FROM (
SELECT event_id
,generate_series(starts_at
,COALESCE(ends_at, starts_at)
,interval '1 day') AS day
,price / COALESCE((ends_at - starts_at) + 1, 1) AS daily
FROM events
) a
GROUP BY 1,2
ORDER BY 1,2;
I provided an updated sqlfiddle for PostgreSQL. Your original seems to be for MySQL.
generate_series()
to create one row per day for every event. COALESCE
to take care of NULL
values, which seem to be allowed for ends_at
. daily
cost by dividing the price by the number of days between starts_at
and ends_at
+ 1
to fix off-by-one. Default to 1 in case of ends_at IS NULL
. Voilá.
You even get exact rates per month, depending on how many days a month has. February (28 days) is cheaper than January (31 days).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.