我有以下代码:
@posts = Post.joins(:user).joins(:blog).select
旨在查找所有帖子并返回它们以及相关的用户和博客。但是,用户是可选的,这意味着INNER JOIN
该:joins
生成没有返回大量记录。
如何使用它来生成一个LEFT OUTER JOIN
?
Answers:
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").
joins(:blog).select
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").joins(:blog).where("users.id IS NULL").select
select('posts.*')
吗?
您可以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)
includes
,不执行联接,而是执行单独的查询以获取关联。因此,它避免了N + 1,但避免了与在一个查询中获取记录的JOIN不同的方式。
includes
,则会生成2个查询,而不是一个查询。JOIN
WHERE
references(:comments)
。另外,由于,这将导致所有返回的注释都急切地加载到内存中includes
,这可能不是您想要的。
Post.includes(:comments).where(comments: {visible: true})
。这样,您也无需使用references
。
默认情况下,当您传递ActiveRecord::Base#joins
命名关联时,它将执行INNER JOIN。您必须传递一个表示您的LEFT OUTER JOIN的字符串。
从文档中:
:joins
-用于附加连接的SQL片段,例如“LEFT JOIN comments ON comments.post_id = id
”(非常需要),用于该:include
选项的相同形式的命名关联,它将对关联的表执行INNER JOIN,或者包含两个字符串的混合数组和命名的协会。如果该值为字符串,则记录将以只读方式返回,因为它们将具有与表的列不对应的属性。传递
:readonly => false
以覆盖。
activerecord中有一个left_outer_joins方法。您可以像这样使用它:
@posts = Post.left_outer_joins(:user).joins(:blog).select
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")