在 Rails 3中的 LEFT OUTER 连接

我有以下密码:

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

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

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

66374 次浏览

By default when you pass ActiveRecord::Base#joins a named association, it will perform an INNER JOIN. You'll have to pass a string representing your LEFT OUTER JOIN.

From the documentation:

:joins - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed), named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s), or an array containing a mixture of both strings and named associations.

If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table‘s columns. Pass :readonly => false to override.

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

You can do with this with includes as documented in the Rails guide:

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

Results in:

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)

I'm a big fan of the squeel gem:

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

It supports both inner and outer joins, as well as the ability to specify a class/type for polymorphic belongs_to relationships.

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")

Use eager_load:

@posts = Post.eager_load(:user)

There is a left_outer_joins method in activerecord. You can use it like this:

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

Good news, Rails 5 now supports LEFT OUTER JOIN. Your query would now look like:

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