【问题标题】:How can I do a LEFT OUTER JOIN using Rails ActiveRecord?如何使用 Rails ActiveRecord 进行 LEFT OUTER JOIN?
【发布时间】:2011-12-22 22:48:16
【问题描述】:

我没有任何想法。你能给我任何线索(比如参考网站)。任何帮助将不胜感激。

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

【问题讨论】:

标签: ruby-on-rails ruby activerecord


【解决方案1】:

如果您对includes 关联使用的表执行条件,我相信includes 将使用LEFT OUTER JOIN 查询:

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

【讨论】:

  • 在这里不起作用(Rails 3.2.7):在includes-referenced 关系上使用条件会引发StatementInvalid 异常,抱怨它错过了FROM-clause entry。我需要添加对join 的显式调用,默认为inner。
  • 你对stackoverflow.com/questions/8025429/…有什么看法?
  • 如果您担心过滤,请定义另一个关联到同一个类并为您应用过滤的关联。
  • 如果你真的讨厌字符串,喜欢符号和哈希(不是火箭),你可以这样做Group.includes(:user_group_cmb).where(user_group_cmbs: { user_id: 1})
  • 或:Group.eager_load(:user_group_cmb).where('user_group_cmbs.user_id = ?', 1)eager_load 总是执行左连接(而 includes 默认执行两个单独的查询)。但要小心使用includeseager_load 生成的左连接,因为它可能会破坏自定义select 子句。
【解决方案2】:

Rails 5+ 允许您执行以下操作:

Group.left_outer_joins(:user_group_cmb)

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

【讨论】:

    【解决方案3】:

    无论您是否在 where 子句中引用表,您都可以在 rails 3.x 中执行此操作:

    Group.eager_load(:user_group_cmb)
    

    ...它将执行左外连接

    【讨论】:

      【解决方案4】:

      提到using includes 可能有不想要的副作用可能很重要。

      如果过滤后的关联随后被限定范围,则所有 原来的过滤消失了

      事实证明,通过限定过滤后的关联,我们丢失了任何 我们从包含中获得的过滤作为副作用。它不是 也是因为我们的搜索方式。

      请务必阅读完整的文章,或者a gem for that

      【讨论】:

        【解决方案5】:

        接受答案的问题在于,它实际上会在技术上执行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)
        

        阅读更详细的解释here

        【讨论】:

          【解决方案6】:

          使用自定义连接语句:

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

          【讨论】:

            【解决方案7】:

            如果您只需要将用户链接到组,请使用 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
            

            【讨论】:

            • 没错,正如你所说,我必须关心用户。我会试试的。
            【解决方案8】:

            无法评论较早的答案,因为我没有 50 声望。 但是当我遇到以下错误时,这就是它对我的工作方式

            includes-referenced 关系引发 StatementInvalid 异常,抱怨它错过了 FROM 子句条目。我需要添加一个显式调用加入,默认为内部。

            我必须使用 .references 并提及表名,或者将其添加到 FROM 子句中

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-06-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-07-23
              • 2014-08-10
              • 2014-01-07
              相关资源
              最近更新 更多