LEFT OUTER se une a Rails 3


86

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 JOINque :joinsgenera no devuelve muchos registros.

¿Cómo utilizo esto para generar un LEFT OUTER JOINen su lugar?


Consulte también LEFT OUTER JOIN en Rails 4
Yarin

Respuestas:


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

3
¿Y si solo quisieras las publicaciones que no tienen usuario?
mcr

24
@mcr@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").joins(:blog).where("users.id IS NULL").select
Linus Oleander

1
¿No necesita seleccionar un parámetro? ¿No debería ser esto select('posts.*')?
Kevin Sylvestre

En Rails 3, esta es la única forma de tener un verdadero control sobre sus combinaciones y saber exactamente qué está pasando.
Joshua Pinter

75

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)

14
De mis pruebas includesno 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.
Kris

7
@Kris Tienes razón, en cierto modo. Es algo que debe tener en cuenta porque la includesfunció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/ …
WuTangTan

4
Esto solo responde parcialmente a la pregunta porque includesgenerará 2 consultas en lugar de una JOINsi no necesita el WHERE.
Rodrigue

14
Esto generará una advertencia en Rails 4 a menos que también agregue references(:comments). Además, esto hará que todos los comentarios devueltos se carguen ansiosamente en la memoria debido a includesque posiblemente no sea lo que desea.
Derek Prior

2
Para hacer esto aún más "Railsy": Post.includes(:comments).where(comments: {visible: true}). De esta manera tampoco es necesario usar references.
Michael

11

Soy un gran admirador de la joya squeel :

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

Es compatible con ambos innery se outerune, así como la capacidad de especificar una clase / tipo para las relaciones polimórficas pertenecen a.


10

Utilizar eager_load:

@posts = Post.eager_load(:user)

8

De forma predeterminada, cuando pasa ActiveRecord::Base#joinsuna asociación con nombre, realizará una INNER JOIN. Tendrá que pasar una cadena que represente su LEFT OUTER JOIN.

De la documentación :

:joins- O un fragmento SQL para combinaciones adicionales como " LEFT JOIN comments ON comments.post_id = id" (rara vez se necesita), asociaciones con nombre en la misma forma que se usa para la :includeopción, que realizará una INNER JOIN en las tablas asociadas, o una matriz que contenga una mezcla de ambas cadenas y asociaciones nombradas.

Si el valor es una cadena, los registros se devolverán como de solo lectura, ya que tendrán atributos que no se corresponden con las columnas de la tabla. Pase :readonly => falsepara anular.



4

Buenas noticias, Rails 5 ahora es compatible LEFT OUTER JOIN. Su consulta ahora se vería así:

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

0
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")
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.