使用ActiveRecord

时间:2018-04-25 18:51:07

标签: sql ruby-on-rails ruby activerecord

我在某个时间点显示的Subscription计数图可能是soft_destroyed_at

要做到这一点,我每个月都会运行一个查询,这当然不如一个大的鸣喇叭查询,但我的SQL技能再次让我失望。

以下是我在Ruby中的表现:

months = (0..12).map { |i| i.months.ago.end_of_month }

stats = Hash[months.map do |eom|
  [
    eom.beginning_of_month.to_date,
    Subscription.where(
      'created_at < ?' \
      'AND (soft_destroyed_at IS NULL ' \
      '  OR soft_destroyed_at > ?) ' \
      'AND (suspended_at IS NULL ' \
      '  OR suspended_at > ?)',
      eom, eom, eom
    ).count
  ]
end]

# => { 2018-04-01 => 10, 2018-03-01 => 15, ... }

我如何使用ActiveRecord将其写为一个查询 - 或者如果需要,使用 raw SQL&gt;

数据库是Postgres 10.2,应用程序是Rails 5.2。

谢谢!

1 个答案:

答案 0 :(得分:1)

您可以使用此查询(我在2017年使用了12个月;只需​​根据需要进行更改)。这假设是Postgresql DB,正如您在评论中所说:

query = 
  "select months.month, count(created_at) "\
  "from "\
    "(select DATE '2017-01-01'+(interval '1' month * generate_series(0,11)) as month, "\
            "DATE '2017-02-01'+(interval '1' month * generate_series(0,11)) as next) months "\
    "outer join subscriptions on "\
    "created_at < month and "\
    "(soft_destroyed_at IS NULL or soft_destroyed_at >= next) and "\
    "(suspended_at IS NULL OR suspended_at >= next) "\
  "group by month "\
  "order by month"

results = ActiveRecord::Base.connection.execute(query)

第一个子查询(select内的from)生成:

month                 next
"2017-01-01 00:00:00";"2017-02-01 00:00:00"
"2017-02-01 00:00:00";"2017-03-01 00:00:00"
"2017-03-01 00:00:00";"2017-04-01 00:00:00"
"2017-04-01 00:00:00";"2017-05-01 00:00:00"
"2017-05-01 00:00:00";"2017-06-01 00:00:00"
"2017-06-01 00:00:00";"2017-07-01 00:00:00"
"2017-07-01 00:00:00";"2017-08-01 00:00:00"
"2017-08-01 00:00:00";"2017-09-01 00:00:00"
"2017-09-01 00:00:00";"2017-10-01 00:00:00"
"2017-10-01 00:00:00";"2017-11-01 00:00:00"
"2017-11-01 00:00:00";"2017-12-01 00:00:00"
"2017-12-01 00:00:00";"2018-01-01 00:00:00"

接下来仅用于更容易检查订阅是否至少在下个月之前处于活动状态(销毁或暂停是&gt; = next(这保证订户在当月处于活动状态)。