2

Railsでコホート分析クエリを実行しようとしていますが、最後のアクション日付でグループ化する正しい方法で問題が発生しています。

次のようなデータの行になりたいです:http ://www.quickcohort.com/

count first_action last_action

昨年登録したすべてのユーザー向け。first_actionそしてlast_action、最も近い月に切り捨てられます。

カウントをグループ化するのfirst_actionは簡単ですが、それを拡張して、last_action遭遇したものを含めるようにしようとすると、

ActiveRecord::StatementInvalid: PGError: ERROR:  aggregates not allowed in GROUP BY clause

これが私がこれまでに持っているものです

User
  .select("COUNT(*) AS count,
    date_trunc('month', users.created_at) AS first_action,
    MAX(date_trunc('month', visits.created_at)) AS last_action # <= Problem
  ")
  .joins(:visits)
  .group("first_action, last_action") # TODO: Subquery ?
  .order("first_action ASC, last_action ASC")
  .where("users.created_at >= date_trunc('month', CAST(? AS timestamp))", 12.months.ago)

訪問数テーブルは、ユーザーがサイトに対して行ったすべての訪問を追跡します。最新の訪問を最後のアクションとして使用するのは簡単なようですが、SQLに変換するのに問題があります。

より良い方法があれば、他のソリューションも利用できますが、単一のSQLクエリが最もパフォーマンスが高いようです。

4

1 に答える 1

2

サブクエリでこれを行う必要があると思います。何かのようなもの:

select first_action, last_action, count(1)
from (
    select
        date_trunc('month', visits.created_at) as first_action,
        max(date_trunc('month', visits.created_at)) as last_action
    from visits
    join users on users.id = visits.user_id
    where users.created_at >= ?
    group by user_id
)
group by first_action, last_action;

ARelでこれを行うのに最もエレガントな方法が何であるかはわかりませんが、このようなものになると思います。(SQLを直接使用する方が簡単な場合があります。)

def date_trunc_month(field)
  Arel::Nodes::NamedFunction.new(
    'date_trunc', [Arel.sql("'month'"), field])
end

def max(*expressions)
  Arel::Nodes::Max.new(expressions)
end

users = User.arel_table
visits = Visit.arel_table

user_visits = visits.
    join(users).on(visits[:user_id].eq(users[:id])).
    where(users[:created_at].gteq(12.months)).
    group(users[:id]).
    project(
        users[:id],
        date_trunc_month(visits[:created_at]).as('first_visit'),
        max(date_trunc_month(visits[:created_at])).as('last_visit')
    ).
    as('user_visits')

cohort_data = users.
    join(user_visits).on(users[:id].eq(user_visits[:id])).
    group(user_visits[:first_visit], user_visits[:last_visit]).
    project(
        user_visits[:first_visit],
        user_visits[:last_visit],
        Arel::Nodes::Count.new([1]).as('count')
    )
于 2013-01-01T20:07:42.733 に答える