如何查找连接表中没有行的随机项?

在我的Rails 4应用程序中,我有一个Item模型和一个Flag模型。 项目has_many标志。 标志belong_to物品。 Flag具有item_iduser_idreason属性。 我需要一种方法来查找未标记的随机待处理项。 我正在使用enum待处理状态。

我相信我可以找到一个标记为的随机待处理项目:

 @pending_item = Item.pending.joins(:flags).order("RANDOM()").first 

但是如何找到未标记的随机待处理项?

使用not exists来获取没有FlagItem

 @pending_item = Item.pending. where("not exists (select 1 from flags where flags.item_id = items.id)"). order("RANDOM()").first 

附注: order("RANDOM()").first如果有许多符合条件的Item ,则order("RANDOM()").first效率不高。 对于大型表,这可能更有效:

 unflagged_pending_items = Item.pending. where("not exists (select 1 from flags where flags.item_id = items.id)") @pending_item = unflagged_pending_items.offset(rand unflagged_pending_items.count).first 

或者,如果第一个查询不是太慢而且每次都不需要不同的随机项,则可以暂时缓存结果。

我不知道,使用子选择是否更好。 我更喜欢使用ID和外键,我可以使用它。

 # initialize my instance variable to have it in the view always @pending_item = nil # get an array with all flagged item ids flagged_item_ids = Flag.group(:item_id).pluck(:item_id) # search for an unflagged item, if there are item ids in the array only, # because the statement could return a flagged item with an empty array in the condition if flagged_item_ids > 0 @pending_item = Item.pending.where.not(id: flagged_item_ids).order("RANDOM()").first end @pending_item # => an unflagged random item or nil 

请记住,数组flagged_item_ids可能包含大量标记的项ID。 这会占用大量内存。

解决方案#1

 Item.pending.joins("LEFT OUTER JOIN ( SELECT id, item_id FROM flags ) AS temp ON temp.item_id = items.id") .where('temp.id = null') .order("RANDOM()") .first 

因此,如果我们使用LEFT OUTER JOIN ,如果该项没有被标记, temp.id将等于null

解决方案#2

 Item.pending.where("id NOT IN ( SELECT item_id FROM flags )") .order("RAMDOM()") .first 

很明显,我们发现一个没有标记的项目。