LoginSignup
45
41

More than 5 years have passed since last update.

ActiveRecordでサブクエリのJOIN

Last updated at Posted at 2015-05-20

たとえば

「ユーザー1がコメントした記事の中で、コメントのlike数が1以上の記事を検索する」

SELECT `posts`.* 
FROM `posts` 
  INNER JOIN (
    SELECT `comments`.* 
    FROM `comments`
    WHERE 
      `comments`.`user_id` = 1 AND
      `comments`.`likes_count` >= 1
  ) liked_user_comments ON liked_user_comments.`post_id` = `posts`.`id`

こんなのをRailsで書くには?

コード

Arel::Table オブジェクトの取得

user = User.find(1)
posts = Post.arel_table
comments = Comment.arel_table 

サブクエリの組み立て

.project などによってできる Arel::SelectManagerオブジェクト の .as を呼ぶと Arel::Nodes::TableAliasオブジェクト を得ることができ、テーブルと同様に扱うことができるようになります。

liked_user_comments = comments
                          .project(Arel.sql('*'))
                          .where(comments[:user_id]
                              .eq(user.id)
                              .and(comments[:likes_count].gtdq(1)))
                          .as('liked_user_comments') # これ

JOIN句の組み立て

先ほど得た Arel::Nodes::TableAlias を .join に渡すとサブクエリになります。
最後に .join_sources を呼ぶことでJOINの右辺を取り出すことができます。(Arel::Nodes::InnerJoinオブジェクト)

join_conds = posts
                 .join(liked_user_comments, Arel::Nodes::InnerJoin)
                 .on(liked_user_comments[:post_id].eq(posts[:id]))
                 .join_sources

ActiveRecord の joins に渡す

Post.joins(join_conds)

参考

45
41
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
41