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

时间:2016-05-09 01:37:50

标签: ruby-on-rails activerecord arel

我想找到courses至少有variant variant_type = 1且variant variant_type = 2的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有许多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}]}

我在where子句中使用原始查询,我想使用Active记录接口或Arel来改进它,对此有什么解决方案吗?

谢谢!

使用输入

更新预期输出

输入

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

输出

rake deploy

5 个答案:

答案 0 :(得分:4)

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

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')

您可能需要更换&#39; non_type_3_variants_courses&#39;使用ARel在进行连接时生成的正确别名(我没有Rails环境)

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

试试这个:

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

希望这有帮助。 :)

答案 3 :(得分:1)

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

你可以在Rails中为第二个查询执行此操作:

 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")

答案 4 :(得分:0)

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

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