如何仅从连接表中选择唯一条目

时间:2015-01-15 09:54:19

标签: sql ruby-on-rails

我想让我的代码块更有效率。我有两个模型和一个连接表。他们都有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&amp; 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的方法,我一直在谷歌上搜索,但到目前为止还没有任何工作。

2 个答案:

答案 0 :(得分:0)

我也是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的部分。

答案 1 :(得分:0)

这个原始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(支持活动记录的查询生成部分)可以生成此类查询,但不会直接公开。