Rails协会不是EXISTS。更好的方法?

时间:2012-11-21 15:21:51

标签: ruby-on-rails sqlite ruby-on-rails-3.2

使用Rails 3.2.9
我正在尝试获取与没有所有者的组织关联的项目列表。

我能够使用下面的数据列表,但对我来说似乎很难看。有更好的方法吗?

Items.all(:select => "items.id, items.name",
  :joins => "INNER JOIN organizations on items.organization_id = organizations.id",
  :conditions => "NOT EXISTS (select * from items k JOIN items_owners on items.id = items_owners.item_id) and items.organization_id = 1")

表格设置:
业主:

  • ID
  • 名称

项目:

  • ID
  • 名称
  • 的organization_ID

items_owners:

  • owner_id
  • ITEM_ID

组织:

  • ID
  • 列表项

型号:

class Organization < ActiveRecord::Base
   attr_accessible :name

   has_many :items
end

class Item < ActiveRecord::Base
   attr_accessible :description, :name, :owner_ids, :organization_id

   has_many :items_owner
   has_many :owners, :through => :items_owner
   belongs_to :organization
end

class Owner < ActiveRecord::Base
   attr_accessible :name

   has_many :items_owner
   has_many :items, :through => :items_owner
end

class ItemsOwner < ActiveRecord::Base
   attr_accessible :owner_id, :item_id

   belongs_to :item
   belongs_to :owner
end

3 个答案:

答案 0 :(得分:7)

  

编辑:删除了.all,添加了references并添加了使用arel_table

Items.joins(:organization).includes(:owners).references(:owners).
  where('owners.id IS NULL')

如果你想同时使用includes

Items.includes(:organization, :owners).references(:organization, :owners).
  where('organisations.id IS NOT NULL AND owners.id IS NULL')

正如@Dario Barrionuevo所写,它应该是belongs_to:Item in

在第一个示例中使用arel_table

Items.joins(:organization).includes(:owners).references(:owners).
  where(Owner.arel_table[:id].eq(nil))
  

在Rails 5中(来自@aNoble的评论):

Items.joins(:organization).left_joins(:owners).
  where(Owner.arel_table[:id].eq(nil))

但是如果应该在代码中引用关系,那么使用includes仍然是可取的,以避免额外的读取。

答案 1 :(得分:1)

有多种方法可以使Rails 5、6不存在:

  1. 与众不同的商品外部加入 item_owners,其中item_owners.id为空
  2. items.id 不能输入(从item_owners中选择item_id)
  3. 不存在(从item_owners中选择1,其中item_id = items.id)
  4. 位置(从item_owners中选择 COUNT (*),其中item_id = items.id)= 0

我能想到4种方法,但我似乎还记得有7种方法。无论如何,这是一个切线,但可能会为您提供一些更适合您的用例的想法。

我发现使用NOT IN方法对我的团队来说是最容易创建和维护的。 我们的目标是避免使用arel,在owner表(例如admin owner)中支持WHERE子句,并支持多层次的rails:through。

Items.where.not(id: Items.joins(:owners).select(:id))
     .select(:id, :name)

Items.where.not(id: Items.joins(:items_owners).select(:id))
     .select(:id, :name)

Items.where.not(id: ItemOwners.select(:item_id))

我们使用第一个,但是这些示例应该按照从最小优化到最佳的顺序排列。也是为了从对模型的知识最少到对知识的了解最多。

答案 2 :(得分:0)

试试这个

Items.joins(:organisations).where(Items.joins(:items_owners).exists.not).select('items.id,items.name')