【问题标题】:How to select only unique entries from a join table如何从连接表中仅选择唯一条目
【发布时间】:2015-01-15 09:54:18
【问题描述】:

我想让我的代码块更有效率。我有两个模型和一个连接表。他们都有has_many :through 关系。有些部分属于多个组,有些只属于一个组。我需要以最有效的方式获取属于 一个组的记录,因为有数千个部分。这是我的模型:

part.rb

class Part < ActiveRecord::Base
  attr_accessible     :name,
                      :group_ids

  has_many            :part_groups, dependent: :destroy
  has_many            :groups, through: :part_groups, select: 'groups.*, part_groups.*'
end

group.rb

class Group < ActiveRecord::Base
  attr_accessible     :name,
                      :part_ids

  has_many            :part_groups, dependent: :destroy
  has_many            :parts, through: :part_groups, select: 'parts.*, part_groups.*'
end

part_group.rb

class PartGroup < ActiveRecord::Base
  attr_accessible :part_id,
                  :group_id 


  belongs_to      :part
  belongs_to      :group
end

我想做的是得到所有只属于Group A和只属于Group B的部分,而不是属于A和B的部分。经过几个小时的努力并得到我无处将其用作权宜之计:

@groupA = []
@groupB = []
Part.all.each do |part|
  if part.group_ids.length == 1 
    if part.group_ids.first == 1
      @groupA.push(part)
    elsif part.group_ids.first == 2
      @groupB.push(part)
    end
  end
end

这显然是不可扩展的,因为会有很多组。我尝试了joininclude 的各种方法,我一直在谷歌搜索,但到目前为止没有任何效果。

【问题讨论】:

    标签: sql ruby-on-rails


    【解决方案1】:

    我也是 Rails 新手,据我所知,这是您的表格的结构。

    零件

    Id | Name

    Id | Name

    part_groups

    Id | part_id | group_id

    因此您可以执行以下操作,

    Group.find(1).parts // Parts belong to group A
    Group.find(2).parts // Parts belong to group B

    所以这也可能给出属于其他组的部分。 目标是获取仅属于 A 组且仅属于 B 组的零件

    试试

    Group.find(1).parts.collect{|row| row if row.groups.count==1}.flatten

    我认为这比你的方法更好,因为我只遍历属于 group1 的那些部分。

    【讨论】:

    • 这就是设置,但是每个都将返回两个组中的零件实例。例如,假设我有 2 个部分在 group A 中,3 个部分在 group B 中,但 part 1part 4group Agroup B 中。 Group.find(1).parts 将返回 [part 1, part 2, part 4] 我只想返回 part 2,因为它在 group A 中是 ONLY
    • 对于小型数据集,这应该可以正常工作,但是,对于较大的数据集,它将生成大量的数据库请求,这将严重滞后于应用程序。这就是我寻找 SQL 解决方案的原因。
    【解决方案2】:

    用于此的原始 sql 可能如下所示

    select parts.* from parts
    inner join part_groups on parts.id = part_groups.part_id
    left outer join part_groups as group_b on group_b.part_id = parts.id and group_b.group_id = 456
    where group_b.id is null and part_groups.group_id = 123
    

    假设组 a 的 id 为 123,组 b 的 id 为 456。

    这样做是尝试加入 part_groups 表两次(因此第二次需要使用别名),一次是 group_id 匹配组 A,一次是针对组 B。使用左连接允许我们要求第二个连接(针对 B)不产生任何行。

    Activerecord 并没有为此提供太多帮助,除了允许您将任意 sql 片段传递给joins,因此您最终会得到类似

    Part.select("parts.*").
          .joins(:part_groups).
          .joins("left outer join part_groups as group_b on group_b.group_id = #{groupb.id} and group_b.part_id = parts.id").
           .where(:part_groups => {:group_id => groupa.id}).where("group_b.id is null")
    

    Arel(支持活动记录的查询生成部分)可以生成这种查询,但这不是直接公开的。

    【讨论】:

      猜你喜欢
      • 2019-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-27
      • 1970-01-01
      • 2017-08-11
      相关资源
      最近更新 更多