LEFTOUTERがRails3に参加


86

私は次のコードを持っています:

@posts = Post.joins(:user).joins(:blog).select

これは、すべての投稿を検索し、それらと関連するユーザーおよびブログを返すことを目的としています。ただし、ユーザーはオプションです。つまり、INNER JOIN:joins生成大量のレコードを返しません。

これを使用してLEFT OUTER JOIN代わりに生成するにはどうすればよいですか?


回答:


111
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").
              joins(:blog).select

3
ユーザーがいない投稿のみが必要な場合はどうなりますか?
mcr 2011

24
@mcr@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").joins(:blog).where("users.id IS NULL").select
Linus Oleander

1
選択にはパラメータが必要ではありませんか?これはすべきではありませんselect('posts.*')か?
Kevin Sylvestre 2015年

Rails 3では、これが結合を真に制御し、何が起こっているのかを正確に知る唯一の方法です。
Joshua Pinter 2018年

75

includes Railsガイドに記載されているようにこれを使用できます。

Post.includes(:comments).where(comments: {visible: true})

結果:

SELECT "posts"."id" AS t0_r0, ...
       "comments"."updated_at" AS t1_r5
FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id"
WHERE (comments.visible = 1)

14
私のテストでincludesは、結合は行いませんが、関連付けを取得するための個別のクエリを実行します。したがって、N + 1を回避しますが、レコードが1つのクエリでフェッチされるJOINと同じ方法ではありません。
クリス

7
@Krisある意味、その通りです。このincludes関数は、使用しているコンテキストに応じて両方を実行するため、注意が必要です。Rails
WuTangTan 2013

4
の必要がない場合includesは、の代わりに2つのクエリが生成されるため、これは質問に部分的にしか答えJOINませんWHERE
ロドリゲ

14
これにより、も追加しない限り、Rails4で警告が生成されますreferences(:comments)。さらに、これにより、返されるすべてのコメントがメモリに熱心にロードされますincludes。これは、おそらくあなたが望むものではありません。
デレク前

2
これをさらに「Railsy」にするには:Post.includes(:comments).where(comments: {visible: true})。このように、を使用する必要もありませんreferences
マイケル2016

11

私はの大ファンです squeelgemの

Post.joins{user.outer}.joins{blog}

innerouter結合の両方をサポートし、ポリモーフィックなbelongs_to関係のクラス/タイプを指定する機能もサポートします。



8

デフォルトではActiveRecord::Base#joins、名前付きアソシエーションを渡すと、内部結合が実行されます。LEFT OUTERJOINを表す文字列を渡す必要があります。

ドキュメントから:

:joins-" LEFT JOIN comments ON comments.post_id = id"(めったに必要ありません)のような追加の結合用のSQLフラグメント、またはに使用されるのと同じ形式の名前付き関連付け:includeオプションにられたテーブルでINNER JOINを実行するか、両方の文字列の混合を含む配列のいずれかです。と名前付きの関連付け。

値が文字列の場合、レコードにはテーブルの列に対応しない属性があるため、レコードは読み取り専用で返されます。:readonly => falseオーバーライドするために渡し ます。



4

朗報です。Rails5はをサポートするようになりましたLEFT OUTER JOIN。クエリは次のようになります。

@posts = Post.left_outer_joins(:user, :blog)

0
class User < ActiveRecord::Base
     has_many :friends, :foreign_key=>"u_from",:class_name=>"Friend"
end

class Friend < ActiveRecord::Base
     belongs_to :user
end


friends = user.friends.where(:u_req_status=>2).joins("LEFT OUTER JOIN users ON users.u_id = friends.u_to").select("friend_id,u_from,u_to,u_first_name,u_last_name,u_email,u_fbid,u_twtid,u_picture_url,u_quote")
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.