TransWikia.com

複数カラムでGroupした結果をHashでなくActiveRecord::relationで取得したい

スタック・オーバーフロー Asked by hatsu on September 1, 2021

やりたいこと

Userが例えば 生まれた年(=year)出身の都道府県(:prefecture_id)カラムを持っているとします。

そこから 「同じ生まれ年」かつ「同じ出身都道府県」のユーザーが3人以上いる場合、そのユーザーの一覧を取得したいです。

出力結果がHashであるため期待する結果ではないのですが、集計して多い順に並び替える処理は以下で出来ました。

User.group(:year, :prefecture_id).having("count_all > 3").order("count_all DESC").count

この出力結果は {[1990, 13]=>4, [1996,2]=>3} のように、生まれ年と都道府県ID、一致した数になっています。

ここから、この「生まれ年」と「都道府県ID」を持つユーザーを一覧を取得するにはどのような手段がありますでしょうか?


上でのHashにUserIdがあれば、pluckとwhereを用いて取得することも出来るかと思いましたが、Idがあると適切なGroupにならないためそれも出来なかったです。。

試したこと

パフォーマンスは悪いですが、以下などが一応期待した動作でした。
しかしデータ数が10万件とかなるとパフォーマンスが非常に悪いため避けたいと思っています。

user_hash = User.all.group_by{ |user| [ user[:year], user[:prefecture_id] ] }
@users = user_hash.values.select{ |user| 3 < user.size }

One Answer

User.joins(<<~SQL)
  INNER JOIN (
    #{User.select("year, prefecture_id, count(*) as count_all").group(:year, :prefecture_id).having("count_all > ?", 3).to_sql}
  ) as year_pref
  ON users.year = year_pref.year
  AND users.prefecture_id = year_pref.prefecture_id
SQL

のようにすると、望みの User についての relation が得られるのではないか、と思っていますが、いかがでしょうか?

追記@2020/07/21

「該当件数」でソートしたい場合には、 sort 条件を relation に含めれば良いと思っています。 e.g.

User.joins(<<~SQL).order("year_pref.count_all DESC")
  INNER JOIN (
    #{User.select("year, prefecture_id, count(*) as count_all").group(:year, :prefecture_id).having("count_all > ?", 3).to_sql}
  ) as year_pref
  ON users.year = year_pref.year
  AND users.prefecture_id = year_pref.prefecture_id
SQL

Correct answer by Yuki Inoue on September 1, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP