【问题标题】:How do I select a specific record from Many-to-many relationships which does not contain a specific item in Rails 2?如何从多对多关系中选择不包含 Rails 2 中特定项目的特定记录?
【发布时间】:2010-12-14 15:22:23
【问题描述】:

我坚持了几个小时。这可能是一个快速的解决方案,但我的大脑现在过热了。好的,就是这样。

我有 Session 和 SessionType 模型,它们之间存在多对多关系,如下所示。

class Session < ActiveRecord::Base
  ...
  has_and_belongs_to_many :session_types
  ...
end

class SessionType < ActiveRecord::Base
  ...
  has_and_belongs_to_many :sessions
  ...
end

我想要的是获得一个不包含任何特定 session_type 的会话,例如,

Session.find(:all, :joins => [:session_types], :conditions => ["session_types.id <> 44"])

这对我不起作用,因为由于多对多关系的性质,上述查询仍会为我提供在其许多关联中具有 session_types.id "44" 的会话。

以下 mysql 代码也不能正常工作。

select sessions.* from sessions
INNER JOIN `session_types_sessions` ON `session_types_sessions`.session_id = `sessions`.id 
WHERE (  session_types_sessions.session_type_id NOT IN (44))
GROUP BY sessions.id

任何帮助将不胜感激。

谢谢。

【问题讨论】:

    标签: mysql ruby-on-rails model many-to-many


    【解决方案1】:

    首先选择类型为 44 的会话:

    session_types_44 = Session.find(:all, :joins => :session_types, 
      :conditions => { :"session_types.id" => 44 }).uniq
    

    并选择不属于上述情况的会话:

    sessions_without_type_44 = Session.find(:all, 
      :conditions => "id NOT IN (#{session_types_44.join(",")})")
    

    您需要小心,因为如果session_types_44 是空数组,您将收到 SQL 错误。

    并回答您的第二个问题:

    你知道我可以如何改变 SQL 来过滤像“让我有 session_type_id '43', 但他们不能有 '44' 的会话

    sessions_without_type_44 获取结果并使用它。首先选择 SessionType 为 43 并通过关联获取属于该 SessionType 的所有会话,并且它们的 id 在sessions_without_type_44 内:

    SessionType.find(43).sessions.all(:conditions => { 
      :id => sessions_without_type_44 })
    

    【讨论】:

    • 是的,只要稍微改变一下语法,它就可以正常工作,因为我在加入时遇到了一些语法错误。 session_types_44 = Session.find(:all, :joins => :session_types, :conditions => { :"session_types.id" => 44 }).uniq Session.find(:all, :conditions => ["id NOT IN (?)",session_types_44.collect { |s| s.id }])
    【解决方案2】:

    试试这个:

    SELECT sessions.*
    FROM sessions
    LEFT JOIN session_types_sessions ON session_types_sessions.session_id = sessions.id AND session_types_sessions.session_type_id = 44
    WHERE session_types_sessions.session_id IS NULL
    

    【讨论】:

    • 太棒了。在 SQL 中工作。我现在需要找到一种方法来集成到 Rails 中。
    • find_by_sql 怎么样?如果您使用的是 Rails 3,在 AREL 中应该有一个简单的方法。
    • 好的,我应该可以的。就在您可以提供帮助的同时,您是否知道如何更改 SQL 以进行过滤,例如“获取具有 session_type_id '43' 的会话,但它们不能具有 '44'”。谢谢。
    【解决方案3】:

    试试这个:

    Session.all(
      :include => :session_types,
      :conditions => ["session_types.id IS NOT NULL AND session_types.id != ?", 44])
    )
    

    include 选项使用 LEFT JOIN,因此该查询将起作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-21
      • 2020-09-03
      • 1970-01-01
      相关资源
      最近更新 更多