事件范围超过一个月时,按月累计事件成本(在rails 3中)

Sæv*_*var 6 sql postgresql ruby-on-rails date ruby-on-rails-3

我有这个Event模型

class Event < ActiveRecord::Base
  attr_accessible :starts_at, :ends_at, :price
end
Run Code Online (Sandbox Code Playgroud)

一个Event可以是单一的即时事件:

Event.create(:starts_at => Date.today, :ends_at=>nil, :price => 10.0)
Run Code Online (Sandbox Code Playgroud)

它也可以跨越多天或几个月:

Event.create(:starts_at => Date.today, :ends_at => (Date.today + 2.months), :price => 20.0)
Run Code Online (Sandbox Code Playgroud)

我希望将事件的成本按月分解,以便即时事件的成本自然地落入其所属的月份,并且跨越多个月的事件的成本应该在这些月份之间按比例分配.

显然使用SQL会很难处理,但也许有人对此有一些建议?

计算此聚合的最有效方法是什么?

更新:

这是一个明确定义的sqlfiddle数据结构:http://sqlfiddle.com/#!12/a532e/6

我想从这个数据集中得到的是:

( (Date('2013-01-01'), 31.6), (Date('2013-02-01'), 8.4) )
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 3

SELECT event_id\n      ,date_trunc(\'month\', day)::date AS month\n      ,sum(daily) AS price_this_month\nFROM  (\n   SELECT event_id\n         ,generate_series(starts_at\n                         ,COALESCE(ends_at, starts_at)\n                         ,interval \'1 day\') AS day\n         ,price / COALESCE((ends_at - starts_at) + 1, 1) AS daily\n   FROM   events\n   ) a\nGROUP  BY 1,2\nORDER  BY 1,2;\n
Run Code Online (Sandbox Code Playgroud)\n

-> sqlfiddle

\n

我为 PostgreSQL 提供了更新的 sqlfiddle。你的原版似乎是针对 MySQL 的。

\n

技巧是:

\n
    \n
  • 使用generate_series()每天为每个事件创建一行。
  • \n
  • 用于COALESCE照顾NULL价值观,这似乎是允许的ends_at
  • \n
  • 通过将价格除以和daily之间的天数来计算成本\n以修正偏差一。\n如果出现以下情况,则默认为 1starts_atends_at+ 1ends_at IS NULL
  • \n
  • 每个事件和月份重新聚合。
  • \n
\n

瞧\xc3\xa1。

\n

你甚至可以得到准确的费率,具体取决于每月有多少天。2 月(28 天)比 1 月(31 天)便宜。

\n