如何找到id与任何数组不匹配的位置?

时间:2012-06-30 23:59:28

标签: ruby-on-rails ruby

我有一个Workout模型,它拥有并属于许多Equipment模型。我有一些Equipment个ID。我想找到所有未分配Workouts的{​​{1}} Equipment匹配任何Equipment ID数组的array = [2,3,5]

因此,如果我的2我想查找所分配的设备ID不包括35Workout.joins(:equipment).where("equipment.id not in(?)",[2,3,5]).uniq 的所有锻炼。

编辑:

Equipment

假设有五个equipment.id个实例,上面的代码会返回1 s 4Workouts(好)的训练,但也返回部分匹配,例如{{1 } equipment.id = [1,2][1,2,3]

3 个答案:

答案 0 :(得分:2)

有助于考虑查询返回的结果集。

Workout.joins(:equipment).where("equipment.id not in(?)",[2,3,5]).uniq

将所有相关设备加入到他们的训练中。如果锻炼与4个设备相关联,那么你将得到4排锻炼。 where子句只是将4减少到一个较小的数字 - 它不能仅仅因为一个匹配而将它们全部擦除。

您需要做的是为连接本身添加条件。像

这样的东西
select workouts.*
left join equipments_workouts on workout_id = workouts.id and equipment_id in (2,3,5)
where equipment_id is null

应该返回正确的锻炼(它也应该返回0设备的锻炼,但我不知道这是否是一个考虑因素。)

这是通过尝试加入'坏'设备来实现的。因为它是左连接,如果没有找到这样的行,那么结果集仍将包含该锻炼的行,但是equipmnts_workouts的列都设置为null。作为奖励,你不再需要消除重复。

Activerecord没有非常好的方式来编写这样的查询。连接方法将接受任意SQL片段:

Workout.joins("left join equipment_workouts on workout_id = workouts.id and equipment_id in (2,3,5)").
        where("equipment_id is null")

您可能会发现sanitize_sql方法对生成该sql片段非常有用

答案 1 :(得分:1)

Workout.joins(:equipment).merge(Equipment.where("id not in(?)",[2,3,5])).uniq

Workout.joins(:equipment).where("equipments.id not in(?)",[2,3,5]).uniq

你也可以尝试这个,它应该找到所有没有任何设备的锻炼

Workout.includes(:equipment).where("equipments.id not in(?)",[2,3,5])

答案 2 :(得分:0)

这可以改进,但应该有效:

class Workout < ActiveRecord::Base
  scope :without_equipments, lambda{|ids| joins(:equipment).where("equipments.id not in (?)", ids.repeated_permutation(ids.size).map(&:uniq).uniq)}
end
Workout.without_equipments 2,3,5