user_id 別の最新レコードを集計する方法


# 概要

Railsでviewに渡すためのActiveRecord::Relationオブジェクトを準備したいのですが、意図通りに集計できません。`user_id`
毎の最新レコードを集計するというものです。

# 詳細

Statusという入退室モデルがあり、次のような構造をしています。

  * Status 
    * id
    * user_id
    * logged_in
    * logged_out
    * created_at
    * updated_at

各ユーザ (`user_id`) の最新レコード（最後に入室もしくは退室した時間）をviewでユーザ毎に表示させたいのですが、集計の方法がわかりません。

ご教示のほどよろしくお願いします。

# 動作環境

  * Rails 4.2.5
  * ruby 2.2.3




サブクエリを作ることで user_id ごとに集計して、その中でlogged_in が最大の行を選択することができます。

[code]

    Status
      .where(%{
        NOT EXISTS(
          SELECT 1
          FROM statuses s1
          WHERE statuses.user_id = s1.user_id AND
                statuses.logged_in < s1.logged_in
        )
      }).order(:user_id).pluck(:user_id, :logged_in)
    
[/code]

これを実行すると、次のようなSQLクエリが実行されます。

[code]

    SELECT *
    FROM statuses
    WHERE (
      NOT EXISTS(
        SELECT 1
        FROM statuses s1
        WHERE statuses.user_id = s1.user_id AND
              statuses.logged_in < s1.logged_in
      )
    )
    
[/code]

※ARELを使って抽象化した方が良いのですが、テーブルを別名でサブクエリに入れる方法が分からない… (多分できない)

なお、`user_id` と `logged_in` の最大値だけを求めれば良いのであれば、イカのようなコードで取得は出来ます。この場合、`id` などが
`nil` になりますので、気をつけてください。

[code]

    Status
      .group(:user_id)
      .select("user_id, MAX(logged_in) AS logged_in")
    
[/code]

[code]

    SELECT user_id, MAX(logged_in) AS logged_in
    FROM statuses
    GROUP BY user_id
    
[/code]

`user_id` と `logged_in`
以外のフィールドも欲しいと思って、イカのように書いてしまうとSQLの文法エラーになります。これは、`SELECT` 句には、`GROUP BY`
に指定したフィールドと、集約関数以外は指定できないためです。

利用するRDBMSによってはエラーを返しませんが、 **意図通りに動くかはマニュアルを参照してください** 。

[code]

    Status
      .group(:user_id)
      .select("*, MAX(logged_in) AS max_logged_in")
    
[/code]

[code]

    SELECT *, MAX(logged_in) AS max_logged_in
    FROM statuses
    GROUP BY user_id
    
[/code]

