如何在复杂的Rails has_many范围内进行外连接?

问题描述 投票:1回答:1

我的目标是建立一个范围,我可以看到所有已完成的Member对象的课程。

Course由许多Sections组成。每个Quiz有一个Section。每一个Quiz都必须设置为complete才能使Course完整。

例如 :

Course
   Section A -> Quiz A ( Complete )
   Section B -> Quiz B ( Complete )
   Section C -> Quiz C ( Complete )

这是我写这种范围的最佳尝试:

# Member.rb

has_many :completed_courses, -> {
  joins(:quizzes, :sections)
  .where(quizzes: {completed: true})
  .group('members.id HAVING count(sections.quizzes.id) = count(sections.id)')
}, through: :course_members, source: :course  

我缺少的部分是这部分count(sections.quizzes.id),它实际上不是SQL。我不完全确定这会被称为什么样的JOIN,但我需要一些方法来count完成的课程测试,并将该数字与多少部分进行比较。如果它们相等,那意味着所有的测验都已完成。

公平地说,只要知道这种JOIN的名称就可能让我朝着正确的方向前进。


更新

我尝试使用@jamesdevar的回复:

has_many :completed_courses, -> {
  joins(:sections)
  .joins('LEFT JOIN quizzes ON quizzes.section_id = sections.id')
  .having('COUNT(sections.id) = SUM(CASE WHEN quizzes.completed = true THEN 1 ELSE 0 END)')
  .group('courses.id')
}, through: :course_members, source: :course  

但它不应该返回[ ]值。例如,我有这些数据:

->  Course{id: 1}
    -> Section{id: 1, course_id: 1}
        -> Quiz{section_id: 1, member_id: 1, completed: true}

该课程共有一个科。该科可能有数百个与其他会员相关的测验,但对于这个特定的会员,他的测验已经完成。

我认为它与这个SQL比较有关,而不是单个成员所独有的。

.having('COUNT(sections.id) = SUM(CASE WHEN quizzes.completed = true THEN 1 ELSE 0 END)')

生成的实际SQL是这样的:

 SELECT "courses".* FROM "courses" 
 INNER JOIN "sections" ON "sections"."course_id" = "courses"."id" 
 INNER JOIN "course_members" ON "courses"."id" = "course_members"."course_id" 
 LEFT JOIN quizzes ON quizzes.section_id = sections.id 
 WHERE "course_members"."member_id" = $1 
 GROUP BY courses.id 
 HAVING COUNT(sections.id) = SUM(CASE WHEN quizzes.completed = true THEN 1 ELSE 0 END) 
 ORDER BY "courses"."title" 
 ASC  [["member_id", 1121230]]
ruby-on-rails postgresql join scope psql
1个回答
2
投票
has_many :completed_courses, -> {
  joins(:sections)
  .joins('LEFT JOIN quizzes ON quizzes.section_id = sections.id')
  .having('COUNT(sections.id) = SUM(CASE WHEN quizzes.completed = true THEN 1 ELSE 0 END)')
  .group('courses.id')
}, through: :course_members, source: :course

在这种情况下,当每个部分完成quizz时​​,having将按条件过滤每个cources.id组。

© www.soinside.com 2019 - 2024. All rights reserved.