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

时间:2016-05-13 13:25:04

标签: ruby-on-rails ruby rails-activerecord

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

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

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

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

3 个答案:

答案 0 :(得分:1)

使用wherenot exists一起获取Item s而不Flag s:

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

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

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

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

答案 1 :(得分:1)

我不知道,使用子选择是否更好。我更喜欢使用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。这会占用大量内存。

答案 2 :(得分:0)

解决方案#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 JOINtemp.id将等于null,如果该项目未被标记。

解决方案#2

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

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