如何将此原始查询转换为Active记录查询接口或arel?

我想找到至少有一个variant_type = 1的variant并且没有variant_type = 2的任何variantvariant_type

所以我的查询如下:

 Course.where("id IN ( SELECT course_id FROM course_variants WHERE variant_type = 1 ) AND id NOT IN ( SELECT course_id FROM course_variants WHERE variant_type = 2 )") 

此外, course有很多course_variants

我在where子句中使用原始查询,我想使用Active记录接口或Arel来改进它,任何解决方案都适用于此?

谢谢!

使用输入更新预期输出

输入

 course: {id=1, course_variants: [{variant_type: 1}, {variant_type: 2}]} course: {id=2, course_variants: [{variant_type: 1}, {variant_type: 3}]} course: {id=3, course_variants: [{variant_type: 2}, {variant_type: 3}]} 

产量

 course: {id=2, course_variants: [{variant_type: 1}, {variant_type: 3}]} 

您可以稍微调整一下您的模型关联:

 class Course < ActiveRecord::Base has_many :type_1_variants, class_name: "CourseVariant", -> { where(variant_type: 1) } has_many :non_type_3_variants, class_name: "CourseVariant", -> { where.not(variant_type: 3) } end Course.joins(:type_1_variants, :non_type_3_variants).group(:course_id).having('COUNT(course_variants.id) > 0').having('COUNT(non_type_3_variants_courses.id) > 0') 

您可能需要将“non_type_3_variants_courses”替换为ARel在进行连接时生成的正确别名(我没有Rails环境)

您应该使用连接方法连接两个表coursescourse_variants然后在where方法中定义条件,如下所示:

 Course.joins("INNER JOIN course_variants on courses.id = course_variants.course_id") .where("course_variants.variant_type" => 1) 

试试这个:

 Course.where(id: CourseVariant.where(variant_type: 1).pluck(:course_id)).where.not(id: CourseVariant.where(variant_type: 2).pluck(:course_id)) 

希望这有帮助。 🙂

嘿,你可以尝试这种方式,它是优化的方式来找到这样的记录,这里不需要两次火灾:

您可以在Rails pluck中执行此操作以进行第二次查询:

  Course.joins(:course_variants).where(:course_variants => {:variant_type => 1}).where("courses.id not in (?)",CourseVariant.where(:variant_type => 2).pluck(:course_id)) 

您可以在单个查询内部使用查询,这比上面的更快:

 Course.joins(:course_variants).where(:course_variants => {:variant_type => 1}).where("courses.id not in (select course_id from course_variants where variant_type = 2)") 

您可以通过在mysql的单个查询中使用group来执行此操作:

 Course.joins(:course_variants).group("course_variants.course_id").having("SUM(CASE WHEN variant_type = 1 THEN 1 WHEN variant_type = 2 THEN 2 ELSE 0 END) = 1") 

如果您在Course和CourseVarint模型之间有关联,那么您可以执行以下操作:

 Course.joins(:course_variants).where(course_variants: {variant_type: 1}).where.not(course_variants: {variant_type: 2})