0

Ich habe zwei Modelle: ProgramStudent und StudentCheckIn (ein Student kann viele Klassen Check-Ins haben, so StudentCheckIn gehört_to ProgramStudent). Ein ProgramStudent hat eine date_of_rank Date-Spalte, die angibt, wann sie ihren aktuellen Rang erreicht haben.Komplexe Join in Rails

Ich möchte eine Abfrage erstellen, die alle ProgramStudents identifiziert, die seit ihrem date_of_rank mehr als X Check-ins haben.

Das StudentCheckIn Modell hat dieses Gültigkeitsbereich:

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

I eine Abfrage konstruieren kann, die diesen Bereich übergeht, wie folgt:

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

die die folgende SQL erzeugt:

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 

und das wird alle ProgramStudents zurückgeben, die mehr als 15 Check-Ins seit einem festen Datum haben (in Dieser Fall, vor zwei Monaten), aber ich möchte, dass die Abfrage das date_of_rank des einzelnen ProgramStudents verwendet, kein festes Datum. Gibt es eine Möglichkeit, dies mit ActiveRecord zu tun? Wenn nicht, wie würde das mit Raw SQL gemacht?

Antwort

1

Dies ist der SQL Sie zum Zielen sind:

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 

Ich bezweifle, Ihr since Umfang einen Spaltennamen nehmen konnte, da jeder String-Eingang wahrscheinlich entkommen bekommen würde, aber man konnte legte die where Klausel nur in die endgültige 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)