我有一个表格课程
和一个表格志愿人员名册
。课程
包含所有课程的列表,volunteer_rosters
包含教授/协助该课程的志愿者列表。
我想写一个查询,返回没有任何志愿者分配给它的所有课程的列表。这就是正在发生的事情:
courses
-------
id
1
3
4
5
6
volunteer_courses
-----------------
id 1 course_id 1
id 2 course_id 1
id 3 course_id 1
id 5 course_id 3
id 6 course_id 3
以下所有查询都返回
course_id 3
course_id 4
course_id 5
为什么course_id 1(正确)被遗漏,而course_id 3却不是???
Course.joins("LEFT JOIN student_rosters ON courses.id = student_rosters.course_id where student_rosters.course_id is null")
Course.joins("LEFT JOIN student_rosters ON courses.id = student_rosters.course_id").where(student_rosters: {id: nil})
Course.includes(:student_rosters).references(:student_rosters).where(student_rosters: {id: nil})
Course.includes(:student_rosters).references(:student_rosters).where('student_rosters.id = ?', nil)
Course.joins("LEFT JOIN student_rosters ON courses.id = student_rosters.course_id").where(student_rosters: {id: nil})
同样的问题,但没有一个解决方案对我有效:
左侧外部连接轨4
不需要使用join
。试试看:
select id from Courses
where id not in (select course_id from volunteer_courses)
虽然不需要使用join
s,但使用not in
与子查询一起使用是危险的。它并不是你真正想要的。如果子查询中的任何行返回null
值,则外部查询不返回任何内容。一点也不吵架。
为此,我强烈建议使用not exists
,并避免使用带有子查询的not in
:
select c.id
from Courses c
where not exists (select 1 from volunteer_courses vc where vc.course_id = c.id);
或左联接
版本:
select c.id
from Courses c left join
volunteer_courses vc
on vc.course_id = c.id
where vc.course_id is null;
此外,这两个都可以利用volunteer_courses(course_id)
上的索引。