J'ai le code suivant:
@posts = Post.joins(:user).joins(:blog).select
qui est destiné à trouver tous les articles et à les renvoyer ainsi qu'aux utilisateurs et blogs associés. Cependant, les utilisateurs sont facultatifs, ce qui signifie que le INNER JOIN
qui :joins
génère ne renvoie pas beaucoup d'enregistrements.
Comment utiliser ceci pour générer un à la LEFT OUTER JOIN
place?
ruby-on-rails
ruby
activerecord
Neil Middleton
la source
la source
Réponses:
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id"). joins(:blog).select
la source
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").joins(:blog).where("users.id IS NULL").select
select('posts.*')
?Vous pouvez le faire avec
includes
comme indiqué dans le guide Rails :Post.includes(:comments).where(comments: {visible: true})
Résulte 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)
la source
includes
ne fait pas une jointure, mais une requête distincte pour obtenir l'assosiation. Cela évite donc N + 1, mais pas de la même manière qu'un JOIN où les enregistrements sont récupérés en une seule requête.includes
fonction fait les deux, selon le contexte dans lequel vous l'utilisez. Le guide Rails l'explique mieux que moi si vous lisiez l'intégralité de la section 12: guides.rubyonrails.org/ …includes
cela générera 2 requêtes au lieu d'uneJOIN
si vous n'avez pas besoin deWHERE
.references(:comments)
. En outre, cela entraînera le chargement hâtif de tous les commentaires renvoyés en mémoire en raison deincludes
, ce qui n'est peut-être pas ce que vous souhaitez.Post.includes(:comments).where(comments: {visible: true})
. De cette façon, vous n'avez pas non plus besoin d'utiliserreferences
.Je suis un grand fan de la gemme squeel :
Il prend en charge à la fois
inner
et lesouter
jointures, ainsi que la possibilité de spécifier une classe / un type pour les relations polymorphes appart_to.la source
Utilisez
eager_load
:@posts = Post.eager_load(:user)
la source
Par défaut, lorsque vous passez
ActiveRecord::Base#joins
une association nommée, elle effectuera une INNER JOIN. Vous devrez passer une chaîne représentant votre JOINTURE EXTÉRIEURE GAUCHE.De la documentation :
la source
Il y a une left_outer_joins méthode activerecord. Vous pouvez l'utiliser comme ceci:
@posts = Post.left_outer_joins(:user).joins(:blog).select
la source
Bonne nouvelle, Rails 5 prend désormais en charge
LEFT OUTER JOIN
. Votre requête ressemblerait maintenant à:@posts = Post.left_outer_joins(:user, :blog)
la source
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")
la source