Eu tenho o seguinte código:
@posts = Post.joins(:user).joins(:blog).select
que tem como objetivo localizar todas as postagens e retorná-las, bem como aos usuários e blogs associados. No entanto, os usuários são opcionais, o que significa que o INNER JOIN
que :joins
gera não está retornando muitos registros.
Como faço para usar isso para gerar um LEFT OUTER JOIN
?
ruby-on-rails
ruby
activerecord
Neil Middleton
fonte
fonte
Respostas:
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id"). joins(:blog).select
fonte
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").joins(:blog).where("users.id IS NULL").select
select('posts.*')
?Você pode fazer isso
includes
conforme documentado no guia Rails :Post.includes(:comments).where(comments: {visible: true})
Resulta em:
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)
fonte
includes
não faço uma junção, mas uma consulta separada para obter a associação. Portanto, ele evita N + 1, mas não da mesma forma que um JOIN, onde os registros são buscados em uma consulta.includes
função faz as duas coisas, dependendo do contexto em que você está usando. O guia Rails explica isso melhor do que eu poderia se você lesse toda a seção 12: guias.rubyonrails.org/ …includes
irá gerar 2 consultas em vez de umJOIN
se você não precisar doWHERE
.references(:comments)
. Além disso, isso fará com que todos os comentários retornados sejam carregados rapidamente na memória devido aoincludes
, o que possivelmente não é o que você deseja.Post.includes(:comments).where(comments: {visible: true})
. Dessa forma, você também não precisa usarreferences
.Sou um grande fã da joia do squeel :
Ele suporta junções
inner
eouter
junções, bem como a capacidade de especificar uma classe / tipo para relacionamentos polimórficos belongs_to.fonte
Use
eager_load
:@posts = Post.eager_load(:user)
fonte
Por padrão, quando você passa
ActiveRecord::Base#joins
uma associação nomeada, ela executa um INNER JOIN. Você terá que passar uma string representando seu LEFT OUTER JOIN.Da documentação :
fonte
Existe um método left_outer_joins em activerecord. Você pode usá-lo assim:
@posts = Post.left_outer_joins(:user).joins(:blog).select
fonte
Boas notícias, Rails 5 agora suporta
LEFT OUTER JOIN
. Sua consulta agora seria semelhante a:@posts = Post.left_outer_joins(:user, :blog)
fonte
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")
fonte