6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RailsのLEFT OUTER JOINにAND条件を追加する

Last updated at Posted at 2020-01-28

TL;DR

includes文ない時

Book.joins(
  <<~SQL
    LEFT OUTER JOIN `reviews` ON `reviews`.`book_id` = `books`.`id` \
    AND `reviews`.`approved` IS NOT NULL
  SQL
).where.not(bookmarks: { id: nil }).order("`reviews`.`created_at` DESC").distinct

=> Book Load (1.5ms)  SELECT DISTINCT `books`.* FROM `books` LEFT OUTER JOIN `reviews` ON `reviews`.`book_id` = `books`.`id` AND `reviews`.`approved` IS NOT NULL WHERE `bookmarks`.`id` IS NOT NULL ORDER BY `bookmarks`.`created_at` DESC

includes文ある時

こうすれば、reviewsを何らかの処理をしたい時、2度ロードしなくて良いです。

Book.includes(:reviews)
  .joins("LEFT OUTER JOIN `reviews` ON `reviews`.`book_id` = `books`.`id` AND `reviews`.`approved` IS NOT NULL")
  .where.not(bookmarks: { id: nil }).order( "reviews`.`created_at` DESC").distinct
=> Book Load (1.5ms)  SELECT DISTINCT `books`.* FROM `books` LEFT OUTER JOIN `reviews` ON `reviews`.`book_id` = `books`.`id` AND `reviews`.`approved` IS NOT NULL WHERE `bookmarks`.`id` IS NOT NULL ORDER BY `bookmarks`.`created_at` DESC
Review Load (0.3ms)  SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`book_id` IN (5, 9)

詳細

解説

Bookというモデルがあり、それにReviewが投稿されていて、Reviewには承認Flagapprovedがあります。Bookを抽出したいが、承認されたReviewの投稿日created_at順で並びたいです

Models

book.rb
class Book < ApplicationRecord
  has_many :reviews
end
review.rb
class Review < ApplicationRecord
  belongs_to :book
  # `approved`というColumnで承認Flagを保持
end

Methods to SQL

INNER JOIN

Book.joins(:reviews)

=> Book Load (1.0ms)  SELECT  `books`.* FROM `books` INNER JOIN `reviews` ON `reviews`.`book_id` = `books`.`id`

単純のLEFT OUTER JOIN

Book.left_joins(:reviews)

=> Book Load (1.0ms)  SELECT  `books`.* FROM `books` LEFT OUTER JOIN `reviews` ON `reviews`.`book_id` = `books`.`id`

LEFT OUTER JOIN ??? AND ???

Book.joins("LEFT OUTER JOIN `reviews` ON `reviews`.`book_id` = `books`.`id` AND `reviews`.`approved` IS NOT NULL")

=> Book Load (1.5ms)  SELECT `books`.* FROM `books` LEFT OUTER JOIN `reviews` ON `reviews`.`book_id` = `books`.`id` AND `reviews`.`approved` IS NOT NULL

上記仕様の実装例

Book.joins(
  <<~SQL
    LEFT OUTER JOIN `reviews` ON `reviews`.`book_id` = `books`.`id` \
    AND `reviews`.`approved` IS NOT NULL
  SQL
).where.not(bookmarks: { id: nil }).order('`reviews`.`created_at` DESC').distinct

=> Book Load (1.5ms)  SELECT DISTINCT `books`.* FROM `books` LEFT OUTER JOIN `reviews` ON `reviews`.`book_id` = `books`.`id` AND `reviews`.`approved` IS NOT NULL WHERE `bookmarks`.`id` IS NOT NULL ORDER BY `bookmarks`.`created_at` DESC

参考

6
7
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
6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?