Rails中的复杂连接

时间:2016-04-12 20:38:56

标签: sql ruby-on-rails postgresql ruby-on-rails-4 rails-activerecord

我有两个模型:ProgramStudent和StudentCheckIn(学生可以有很多课程检查,所以StudentCheckIn属于ProgramStudent)。 ProgramStudent有一个date_of_rank日期列,用于指示他们何时达到当前排名。

我想生成一个查询,以识别自date_of_rank以来具有超过X个签到的所有ProgramStudents。

StudentCheckIn模型具有以下范围:

scope :since, -> (date) { where("checked_in_at >= ?", date) }

我可以构建一个合并此范围的查询,如下所示:

ProgramStudent.joins(:student_check_ins)
    .merge(StudentCheckIn.since(Date.today - 2.months))
    .group("program_students.id")
    .having("count(*) > ?", 15)

生成以下SQL:

SELECT "program_students".* FROM "program_students" 
INNER JOIN "student_check_ins" 
ON "student_check_ins"."program_student_id" = "program_students"."id" 
WHERE (checked_in_at >= '2016-02-12') 
GROUP BY program_students.id 
HAVING count(*) > 15

这将返回自固定日期(在这种情况下,两个月前)以来有超过15次签到的所有ProgramStudents,但我希望查询使用单独的ProgramStudent的date_of_rank,而不是固定的日期。有没有办法用ActiveRecord做到这一点?如果没有,那么如何使用原始SQL?

1 个答案:

答案 0 :(得分:1)

这是您的目标:

SELECT "program_students".* FROM "program_students" 
INNER JOIN "student_check_ins" 
ON "student_check_ins"."program_student_id" = "program_students"."id" 
WHERE (checked_in_at >= "program_students"."date_of_rank") 
GROUP BY program_students.id, program_students.date_of_rank 
HAVING count(*) > 15

我怀疑你的since范围可以采用列名,因为任何字符串输入都可能被转义,但你可以将where子句放在最终的ARel中:

ProgramStudent.joins(:student_check_ins).
  where("student_check_ins.checked_in_at >= program_students.date_of_rank").
  group("program_students.id, program_students.date_of_rank").
  having("count(*) > ?", 15)