Подтвердить что ты не робот

Как я могу сделать 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

4b9b3361

Ответ 1

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

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

Ответ 3

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

Group.eager_load(:user_group_cmb)

... и он выполнит соединение с левым фокусом

Ответ 4

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

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

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

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

Ответ 5

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

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

Ответ 6

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

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

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

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

Group.eager_load(:user_group_cmb)

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

Ответ 7

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

Пример:

class User < ActiveRecord::Base
  has_and_belongs_to_many :groups
end

class Group < ActiveRecord::Base
  has_and_belongs_to_many :users      
end

Ответ 8

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

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

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