如何将此原始查询转换为活动记录查询接口或 arel?
How to convert this raw query to Active record query interface or arel?
我想找到至少有 1 个 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
。
我在 where 子句中使用原始查询,我想使用 Active record 接口或 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}]}
如果你有 Course 和 CourseVarint 模型之间的关联,那么你可以这样做:
Course.joins(:course_variants).where(course_variants: {variant_type: 1}).where.not(course_variants: {variant_type: 2})
你应该使用 joins 方法连接两个表 courses
和 course_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))
您可以在内部查询中使用 in 查询,这比上面更快:
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")
您可以稍微调整一下模型关联:
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 env atm)
我想找到至少有 1 个 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
。
我在 where 子句中使用原始查询,我想使用 Active record 接口或 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}]}
如果你有 Course 和 CourseVarint 模型之间的关联,那么你可以这样做:
Course.joins(:course_variants).where(course_variants: {variant_type: 1}).where.not(course_variants: {variant_type: 2})
你应该使用 joins 方法连接两个表 courses
和 course_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))
您可以在内部查询中使用 in 查询,这比上面更快:
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")
您可以稍微调整一下模型关联:
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 env atm)