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 !!
source to share
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)
source to share