it-roy-ru.com

Как я могу сделать LEFT OUTER JOIN, используя Rails ActiveRecord?

У меня нет никаких идей. Не могли бы вы дать мне какие-либо подсказки (например, ссылки на сайты). Любая помощь будет оценена.

Model1: GROUP(id, name)
Model2: USER_GROUP_CMB(id, user_id, group_id)

Ожидаемый оператор SQL:

SELECT * 
FROM groups AS g LEFT OUTER JOIN user_group_cmbs AS cmb 
            ON g.id = cmb.group_id
WHERE cmb.user_id = 1

Я попытался установить ассоциации ниже, но я не знаю, что делать после этого.

class Group < ActiveRecord::Base
  has_many :user_group_cmb
end

class UserGroupCmb < ActiveRecord::Base
  has_many :group
end

Версия Rails: 3.1.1

19
zono

Я считаю, что includes будет использовать запрос LEFT OUTER JOIN, если вы зададите условие для таблицы, которую использует ассоциация includes:

Group.includes(:user_group_cmb).where(user_group_cmbs: { user_id: 1 })
32
Ryan Bigg

Rails 5+ позволяет вам делать следующее:

Group.left_outer_joins(:user_group_cmb)

http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-left_joins

14
Diego Plentz

Вы можете сделать это в Rails 3.x независимо от того, ссылаетесь вы на таблицу или нет в предложении where:

Group.eager_load(:user_group_cmb)

... и он выполнит левое внешнее соединение

10
knoopx

Возможно, очень важно отметить, что using includes может иметь нежелательные побочные эффекты.

если отфильтрованная ассоциация впоследствии ограничена, все оригинальная фильтрация исчезает

Как выясняется, при определении области отфильтрованной ассоциации мы потеряли любую побочный эффект фильтрации, который мы получили, включает в себя. И это не так. из-за того, как мы искали, либо.

Обязательно прочитайте всю статью, и в качестве альтернативы есть гем для этого .

8
user191766

Используйте пользовательский оператор соединений:

Group.joins("left outer join user_group_cmbs as cmb on groups.id = cmb.group_id")
  .where("cmb.user_id = ?", 1)
7
hammady

Проблема с принятым ответом состоит в том, что он фактически будет выполнять LEFT INNER JOIN технически, потому что он не будет отображать записи, в которых user_group_cmbs. user_id равен нулю (что и послужило бы причиной для создания LEFT OUTER JOIN).

Рабочим решением является использование #references :

Group.includes(:user_group_cmb).references(:user_group_cmb)

Или еще удобнее #eager_load :

Group.eager_load(:user_group_cmb)

Прочитайте более подробное объяснение здесь .

6
KARASZI István

Используйте has_and_belongs_to_many , если вам просто нужно связать пользователей с группами. Используйте has_many: through , если вам нужно сохранить дополнительную информацию о членстве.

Пример:

class User < ActiveRecord::Base
  has_and_belongs_to_many :groups
end

class Group < ActiveRecord::Base
  has_and_belongs_to_many :users      
end
2
panupan

Не могу прокомментировать более ранний ответ, потому что у меня нет 50 репутации .... Но вот как это сработало для меня, когда я столкнулся с ошибкой ниже

отношение include-referenced вызывает исключение StatementInvalid, жалуясь на то, что в нем отсутствует запись предложения FROM. Мне нужно добавить явный вызов join, который по умолчанию является внутренним. 

Я должен был использовать .references и упомянуть имя таблицы или добавить его в FROM-предложение.

0
Raja