我有一个Workout
模型,它拥有并属于许多Equipment
模型。我有一些Equipment
个ID。我想找到所有未分配Workouts
的{{1}} Equipment
匹配任何Equipment
ID数组的array = [2,3,5]
。
因此,如果我的2
我想查找所分配的设备ID不包括3
,5
或Workout.joins(:equipment).where("equipment.id not in(?)",[2,3,5]).uniq
的所有锻炼。
编辑:
Equipment
假设有五个equipment.id
个实例,上面的代码会返回1
s 4
和Workouts
(好)的训练,但也返回部分匹配,例如{{1 } equipment.id
= [1,2]
,[1,2,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