11

使用 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
  • 姓名
  • 组织 ID

物品所有者:

  • 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
4

3 回答 3

10

编辑:删除.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 :organisation in Item

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如果要在代码中引用关系,使用仍然是更可取的,以避免额外的读取。

于 2012-11-21T16:00:13.477 回答
4

在 rails 5、6 中有很多方法可以做到 NOT EXISTS:

  1. 不同的项目OUTER JOIN item_owners 其中 item_owners.id 为空
  2. items.id NOT IN(从 item_owners 中选择 item_id)
  3. 存在(从 item_owners 中选择 1,其中 item_id = items.id)
  4. where (select COUNT (*) from item_owners where item_id = items.id) = 0

在我的脑海中,我可以想到 4 种方法,但我似乎记得有 7 种。无论如何,这是一个切线,但可能会给你一些更适合你的用例的想法。

我发现使用 NOT IN 方法对我的团队来说是最容易创建和维护的。我们的目标是避免 arel,支持 owner 表中的 WHERE 子句(例如:admin owner),并支持多个级别的 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))

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

于 2020-10-19T22:40:15.830 回答
-1

试试这个

Items.joins(:organisations).where(Items.joins(:items_owners).exists.not).select('items.id,items.name')
于 2012-11-21T15:37:07.357 回答