У меня такой код:
@posts = Post.joins(:user).joins(:blog).select
который предназначен для поиска всех сообщений и возврата их, а также связанных пользователей и блогов. Однако пользователи не являются обязательными, что означает, чтоINNER JOIN
что :joins
генерируемый объект не возвращает много записей.
Как мне использовать это для создания LEFT OUTER JOIN
вместо этого?
ruby-on-rails
ruby
activerecord
Нил Миддлтон
источник
источник
Ответы:
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id"). joins(:blog).select
источник
@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").joins(:blog).where("users.id IS NULL").select
select('posts.*')
?Вы можете сделать это,
includes
как описано в руководстве по Rails :Post.includes(:comments).where(comments: {visible: true})
Результаты в:
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)
источник
includes
не выполняется соединение, а выполняется отдельный запрос для получения ассоциации. Таким образом, он избегает N + 1, но не так, как JOIN, когда записи выбираются в одном запросе.includes
функция делает и то, и другое, в зависимости от контекста, в котором вы ее используете. Руководство по Rails объясняет это лучше, чем я мог бы, если бы вы полностью прочитали раздел 12: guides.rubyonrails.org/ …includes
будет генерировать 2 запроса вместо одного,JOIN
если вам не нуженWHERE
.references(:comments)
. Кроме того, это приведет к тому, что все возвращенные комментарии будут загружены в память из-за тогоincludes
, что, возможно, не то, что вам нужно.Post.includes(:comments).where(comments: {visible: true})
. Таким образом, вам также не нужно использоватьreferences
.Я большой поклонник Squeel gem :
Он поддерживает оба типа
inner
иouter
соединения, а также возможность указывать класс / тип для полиморфных отношений own_to.источник
Использование
eager_load
:@posts = Post.eager_load(:user)
источник
По умолчанию при прохождении
ActiveRecord::Base#joins
именованную ассоциацию, она выполняет INNER JOIN. Вам нужно будет передать строку, представляющую ваше LEFT OUTER JOIN.Из документации :
источник
В activerecord есть метод left_outer_joins. Вы можете использовать это так:
@posts = Post.left_outer_joins(:user).joins(:blog).select
источник
Хорошие новости, теперь Rails 5 поддерживает
LEFT OUTER JOIN
. Теперь ваш запрос будет выглядеть так:@posts = Post.left_outer_joins(:user, :blog)
источник
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")
источник