LEFT OUTER加入Rails 3

Nei*_*ton 85 ruby activerecord ruby-on-rails

我有以下代码:

@posts = Post.joins(:user).joins(:blog).select
Run Code Online (Sandbox Code Playgroud)

这是为了查找所有帖子并返回它们以及相关的用户和博客.但是,用户是可选的,这意味着INNER JOIN:joins生成没有返回大量记录.

我如何使用它来生成一个LEFT OUTER JOIN

Nei*_*ton 111

@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").
              joins(:blog).select
Run Code Online (Sandbox Code Playgroud)

  • @mcr `@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").joins(:blog).where("users.id IS NULL").select` (24认同)
  • 如果你只想要没有用户的帖子怎么办? (3认同)

WuT*_*Tan 75

您可以使用includes Rails指南中记录的内容执行此操作:

Post.includes(:comments).where(comments: {visible: true})
Run Code Online (Sandbox Code Playgroud)

结果是:

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)
Run Code Online (Sandbox Code Playgroud)

  • 从我的测试中,`includes`不进行连接,而是进行单独的查询以获得关联.因此它避免了N + 1,但与在一个查询中获取记录的JOIN的方式不同. (14认同)
  • 这将在Rails 4中生成警告,除非您还添加`references(:comments)`.此外,由于`includes`,这将导致所有返回的注释在内存中急切加载,这可能不是您想要的. (14认同)
  • @Kris你在某种程度上是对的.这是你需要注意的事情,因为`includes`函数同时执行这两个功能,具体取决于你使用它的上下文.如果你阅读第12节的全部内容,Rails指南会比我更好地解释它:http:/ /guides.rubyonrails.org/active_record_querying.html#eager-loading-associations (7认同)
  • 这只是部分回答了这个问题,因为如果你不需要`WHERE`,`includes`将生成2个查询而不是`JOIN`. (4认同)
  • 为了使这更"Railsy":`Post.includes(:comments).where(comments:{visible:true})`.这样你也不需要使用`references`. (2认同)

pla*_*mbo 11

我是squeel gem的忠实粉丝:

Post.joins{user.outer}.joins{blog}
Run Code Online (Sandbox Code Playgroud)

它支持both innerouterjoin,以及为多态belongs_to关系指定类/类型的能力.


小智 10

用途eager_load:

@posts = Post.eager_load(:user)
Run Code Online (Sandbox Code Playgroud)


DBA*_*DBA 8

默认情况下,当您传递ActiveRecord::Base#joins命名关联时,它将执行INNER JOIN.你必须传递一个表示你的LEFT OUTER JOIN的字符串.

文档:

:joins- 用于附加连接的SQL片段,如" LEFT JOIN comments ON comments.post_id = id"(很少需要),用于该:include选项的相同形式的命名关联,它将在关联的表上执行INNER JOIN,或者包含两个字符串的混合的数组和命名的协会.

如果值是字符串,则记录将以只读方式返回,因为它们将具有与表的列不对应的属性.传递 :readonly => false覆盖.


Ahm*_*ain 7

activerecord中有一个left_outer_joins方法.你可以像这样使用它:

@posts = Post.left_outer_joins(:user).joins(:blog).select
Run Code Online (Sandbox Code Playgroud)