1

我有一个Workout模型,它拥有并属于许多Equipment模型。Equipment我有一些ID的数组。我想找到所有Workouts没有与任何IDEquipment数组匹配的分配。Equipment

因此,如果我array = [2,3,5]想查找分配的设备 ID 不包括的所有锻炼235.

编辑:

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

假设有 5 个实例,上面的代码返回带有s和(good) 的Equipment锻炼,但也返回部分匹配,例如带有= , 。equipment.id14Workoutsequipment.id[1,2][1,2,3]

4

3 回答 3

2
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])
于 2012-07-01T00:05:21.500 回答
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 个设备的锻炼,但我不知道这是否是一个考虑因素。)

这是通过尝试加入“坏”设备来实现的。因为它是左连接,所以如果找不到这样的行,那么结果集仍将包含该锻炼的行,但equimnts_workouts 的列都设置为空。作为奖励,您不再需要消除重复项。

Activerecord 没有很好的方式来编写这样的查询。joins 方法将接受任意 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 片段很有用

于 2012-07-01T09:12:00.850 回答
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
于 2012-07-01T04:49:10.950 回答