Complex Ruby SQL query using Active Record - WHERE using OR clause and subquery

I am using Ruby 2.0.0 and Rails 4.1.0.

I am trying to translate a complex SQL query to Ruby. I was able to convert most of them, but I have a hard time with the "OR" clause.

Here is the original SQL query:

SELECT DISTINCT "lecture_classes".* 
FROM "lecture_classes" 
INNER JOIN 
    "lectures" ON "lectures"."id" = "lecture_classes"."lecture_id" 
INNER JOIN 
    "weeks" ON "weeks"."id" = "lectures"."week_id"  
WHERE "lectures"."part" = 1 
    AND "weeks"."number" = 1 
    AND "weeks"."course_id" = 1 
    AND(                                          --very important parenthesis start
        "lecture_classes"."id" IN (
        SELECT "lecture_enrollments"."lecture_class_id" 
        FROM "lecture_enrollments"  
        GROUP BY lecture_class_id 
        HAVING count(lecture_class_id) <= 5
        ) 
        OR "lecture_classes"."id"                --this is the OR that needs to have Ruby equivalent
        NOT IN (
            SELECT "lecture_enrollments"."lecture_class_id"
            FROM "lecture_enrollments"
            )  
    )                                           --very important parenthesis ends
ORDER BY "lecture_classes"."class_date" ASC

      

I was able to convert most of them:

@max_students = 5

LectureClass
       .joins(:lecture, lecture: :week)
       .where(lectures: {part: part})
       .where(weeks: {number: week, course_id: course})
       .where(id: LectureEnrollment
                  .select("lecture_class_id")
                  .group("lecture_class_id")
                  .having("count(lecture_class_id) <= ?",@max_students)
                  )
       .distinct
       .order(class_date: :asc)

      

but my biggest struggle involves the "OR" clause ... and note that it must be inside a parenthesis with another clause (noted in the comment) or the result will be wrong.

I know I can do something like

Project.where("manager_user_id = ? OR account_manager = ?", current_user.id, current_user.id)

      

But my problem is that I have no OR value, this is the result of the select expression. How do I write this in Ruby?

Any thoughts?

Thank!

*** UPDATE:

Thanks Drew, it works!

I tried to make it prettier and more Ruby-like based on your previous answer, so I did

@max_students = 5 

LectureClass
       .joins(:lecture, lecture: :week)
       .where(lectures: {part: part})
       .where(weeks: {number: week, course_id: course})
       .where(id: LectureEnrollment
                  .select("lecture_class_id")
                  .group("lecture_class_id")
                  .having("count(lecture_class_id) <= ?",@max_students)
                  )
       .or( LectureClass
            .where
            .not(id:[LectureEnrollment
                          .select(:lecture_class_id)
                     ])
            )
       .distinct
       .order(class_date: :asc)

      

However, I get the error: NoMethodError - undefined method `or '. I suppose this is an AND dependent method ( https://github.com/rails/arel ), but I don't want to add this library just to solve the OR problem. The SQL connection works fine. Thank you !!

+3


source to share


1 answer


How about the next one?



LectureClass
       .joins(:lecture, lecture: :week)
       .where(lectures: {part: part})
       .where(weeks: {number: week, course_id: course})
       .where("lecture_classes.id IN (
        SELECT lecture_class_id
        FROM lecture_enrollments 
        GROUP BY lecture_class_id 
        HAVING count(lecture_class_id) <= ?
        ) 
        OR lecture_classesid
        NOT IN (
            SELECT lecture_class_id
            FROM lecture_enrollments
            )", @max_students)
       .distinct
       .order(class_date: :asc)

      

0


source







All Articles