Tengo el siguiente código:
@posts = Post.joins(:user).joins(:blog).select
que está destinado a encontrar todas las publicaciones y devolverlas y los usuarios y blogs asociados. Sin embargo, los usuarios son opcionales, lo que significa que el INNER JOIN
que :joins
genera no devuelve muchos registros.
¿Cómo utilizo esto para generar un LEFT OUTER JOIN
en su lugar?
ruby-on-rails
ruby
activerecord
Neil Middleton
fuente
fuente
Respuestas:
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id"). joins(:blog).select
fuente
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").joins(:blog).where("users.id IS NULL").select
select('posts.*')
?Puede hacer con esto
includes
como se documenta en la guía Rails :Post.includes(:comments).where(comments: {visible: true})
Resultados en:
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)
fuente
includes
no hace una combinación, sino una consulta separada para obtener la asociación. Por lo tanto, evita N + 1, pero no de la misma manera que JOIN, donde los registros se obtienen en una consulta.includes
función hace ambas cosas, dependiendo del contexto en el que la esté utilizando. La guía Rails lo explica mejor que yo si leyera la sección 12 completa: guides.rubyonrails.org/ …includes
generará 2 consultas en lugar de unaJOIN
si no necesita elWHERE
.references(:comments)
. Además, esto hará que todos los comentarios devueltos se carguen ansiosamente en la memoria debido aincludes
que posiblemente no sea lo que desea.Post.includes(:comments).where(comments: {visible: true})
. De esta manera tampoco es necesario usarreferences
.Soy un gran admirador de la joya squeel :
Es compatible con ambos
inner
y seouter
une, así como la capacidad de especificar una clase / tipo para las relaciones polimórficas pertenecen a.fuente
Utilizar
eager_load
:@posts = Post.eager_load(:user)
fuente
De forma predeterminada, cuando pasa
ActiveRecord::Base#joins
una asociación con nombre, realizará una INNER JOIN. Tendrá que pasar una cadena que represente su LEFT OUTER JOIN.De la documentación :
fuente
Hay una left_outer_joins método en el activerecord. Puedes usarlo así:
@posts = Post.left_outer_joins(:user).joins(:blog).select
fuente
Buenas noticias, Rails 5 ahora es compatible
LEFT OUTER JOIN
. Su consulta ahora se vería así:@posts = Post.left_outer_joins(:user, :blog)
fuente
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")
fuente