我需要获取日期早于当前日期的属于当前用户的所有作业,并且还需要过滤评论为零的作业。
我尝试了以下操作:
Job.joins(:user, :review).where("jobs.date < ? AND jobs.status = ? AND users.id = ?", Time.now, 3 , user.id).group("jobs.id").having("COUNT(reviews) = ?", 0)
在使用特定用户ID(3356)的情况下,我应该获得一份工作,但没有得到。
这是我的模特
class Job < ActiveRecord::Base
belongs_to :user
has_one :review
end
class User < ActiveRecord::Base
has_many :jobs
has_one :reviews
end
class Review < ActiveRecord::Base
belongs_to :job
belongs_to :user
end
status
是一个枚举(必须为3,即为“已接受”)
我在做什么错?我不确定如何正确构造SQL,所以这可能是问题所在。感谢您的帮助。
答案 0 :(得分:2)
您需要执行左外部联接,而不是内部联接,如果您进行内部联接,则如果具有0条评论,则该任务将不起作用。作业必须至少具有一条评论,然后才可以记录该任务的记录,此外,在左外部加入后,将记录所有作业是否经过审查。
Job.left_outer_joins(:user, :reviews).where("jobs.date < ? AND jobs.status = ? AND users.id = ?", Time.now, 3 , user.id).group("jobs.id").having("COUNT(reviews) = ?", 0)
答案 1 :(得分:1)
joins(:review)将执行Job和Review的内部联接,这将导致结果中跳过0条评论的作业。 试试这个:
Job.joins(:user).joins("left join reviews on reviews.job_id = jobs.id ").where("jobs.date < ? AND jobs.status = ? AND users.id = ?", Time.now, 3 , user.id).group("jobs.id").having("COUNT(reviews) = ?", 0)
答案 2 :(得分:1)
我喜欢思考这样的问题的一种方法是将它们分解为较小的问题。
根据您的问题,我们希望...
获取所有作业:
Job.accepted
Job.where(user: current_user)
Job.where('date < ?', Time.zone.today)
reviews = Review.all
Job.where.not(id: reviews.select(:job_id))
此人与其他人稍有不同,使用的是subquery。
现在,让我们将所有这些放在一起,并在Job类中定义一个方法:
class Job < ApplicationRecord
enum status: [:other_status, :accepted]
belongs_to :user
has_one :review
def self.unreviewed(user)
accepted
.where(user: user)
.where('date < ?', Time.zone.today)
.where.not(id: Review.select(:job_id))
end
end
这将生成以下SQL:
irb(main):002:0> puts Job.unreviewed(user).to_sql
SELECT "jobs".* FROM "jobs" WHERE "jobs"."status" = 0 AND "jobs"."user_id" = 1 AND (date < '2019-03-26') AND "jobs"."id" NOT IN (SELECT "reviews"."job_id" FROM "reviews")
您还可以找到some specs testing this here。