LEFT OUTER присоединяется к Rails 3


86

У меня такой код:

@posts = Post.joins(:user).joins(:blog).select

который предназначен для поиска всех сообщений и возврата их, а также связанных пользователей и блогов. Однако пользователи не являются обязательными, что означает, чтоINNER JOIN что :joinsгенерируемый объект не возвращает много записей.

Как мне использовать это для создания LEFT OUTER JOINвместо этого?


Смотрите также LEFT OUTER JOIN in Rails 4
Yarin

Ответы:


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

3
что, если вам нужны только сообщения, у которых нет пользователя?
mcr

24
@mcr@posts = Post.joins("LEFT OUTER JOIN users ON users.id = posts.user_id").joins(:blog).where("users.id IS NULL").select
Линус Олеандр

1
Не выбирает нужен параметр? Разве этого не должно быть select('posts.*')?
Кевин Сильвестр,

В Rails 3 это единственный способ полностью контролировать свои объединения и точно знать, что происходит.
Джошуа Пинтер

75

Вы можете сделать это, 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)

14
Из моих тестов includesне выполняется соединение, а выполняется отдельный запрос для получения ассоциации. Таким образом, он избегает N + 1, но не так, как JOIN, когда записи выбираются в одном запросе.
Крис

7
@Kris.В каком-то смысле ты прав. Это то, на что вам нужно обратить внимание, потому что includesфункция делает и то, и другое, в зависимости от контекста, в котором вы ее используете. Руководство по Rails объясняет это лучше, чем я мог бы, если бы вы полностью прочитали раздел 12: guides.rubyonrails.org/ …
WuTangTan

4
Это лишь частично отвечает на вопрос, потому что includesбудет генерировать 2 запроса вместо одного, JOINесли вам не нужен WHERE.
Rodrigue

14
Это сгенерирует предупреждение в Rails 4, если вы также не добавите references(:comments). Кроме того, это приведет к тому, что все возвращенные комментарии будут загружены в память из-за того includes, что, возможно, не то, что вам нужно.
Derek Prior

2
Чтобы сделать это еще более «Railsy»: Post.includes(:comments).where(comments: {visible: true}). Таким образом, вам также не нужно использовать references.
Майкл

11

Я большой поклонник Squeel gem :

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

Он поддерживает оба типа innerи outerсоединения, а также возможность указывать класс / тип для полиморфных отношений own_to.



8

По умолчанию при прохождении ActiveRecord::Base#joins именованную ассоциацию, она выполняет INNER JOIN. Вам нужно будет передать строку, представляющую ваше LEFT OUTER JOIN.

Из документации :

:joins- Либо фрагмент SQL для дополнительных объединений, таких как " LEFT JOIN comments ON comments.post_id = id" (редко требуется), именованные ассоциации в той же форме, что и для:include параметра, который будет выполнять ВНУТРЕННЕЕ СОЕДИНЕНИЕ для связанной таблицы (таблиц), либо массив, содержащий смесь обеих строк и названные ассоциации.

Если значение является строкой, то записи будут возвращены только для чтения, поскольку они будут иметь атрибуты, не соответствующие столбцам таблицы. Перейти :readonly => falseк переопределению.



4

Хорошие новости, теперь Rails 5 поддерживает LEFT OUTER JOIN. Теперь ваш запрос будет выглядеть так:

@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")
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.