select distinct S.ID, S.name
from student as S
where not exists (
(select course_id from course where dept_name = ’Biology’)
except
(select T.course_id from takes as T where S.ID = T.ID)
);
此查询在我的书中表示
“查找所有修过生物学所有课程的学生 部门”
表如下:
学生(ID,姓名,部门名称,tot_cred)
接受(ID,course_id,sec_id,学期,学年,年级)
课程(课程ID,标题,部门名称,学分)
我以为查询不起作用,因为学生表没有课程ID。
为什么该查询的执行与上述相同?
答案 0 :(得分:2)
我以为查询不起作用,因为学生表没有课程ID。
请注意,除了表192.168.1.x
(IPROUTER = (Left(IP, 10)) & (Mid(IP, 11, 3) + 5)
)或表course_id
(course
)之外,从未引用select course_id from course
。该查询从未引用过takes
,因此您的问题掩盖了您对该查询的误解。
查询有点混乱,因为它有效地使用了双重否定。 select T.course_id from takes as T
子句或多或少说:“如果所有学生都参加了所提供的生物学课程,并删除了该学生所参加的所有课程,则将所有学生都找到哪里,结果将是空的。”
student.course_id
如果我们修读所有提供的生物学课程,并删除该学生已修读的课程,而结果为空集,则唯一可能的解释是该学生已修读所有提供的生物学课程。 (此外:也有可能没有提供生物学课程,在这种情况下,学生仍会修读所有提供的生物学课程-这称为vacuous truth。)
答案 1 :(得分:1)
查询的意思是:“生物学系中没有一个学生没有修过的课程”。
第二个子查询(在except
之后)正在获取该学生参加的所有课程。这些已从生物学系的所有课程中删除。因此,如果某个学生修完了该系的所有课程,那么结果将是没有行。否则,结果是学生未参加的行。
select distinct
极具误导性。学生表不应重复。
我更喜欢对这些类型的查询使用聚合:
select t.student_id
from takes t join
course c
on t.course_id = c.course_id
where c.dept_name = 'Biology'
group by t.student_id
having count(distinct t.course_id) = (select count(*) from course c2 where c2.dept_name = 'Biology');
(至少对我而言),这里的逻辑更加清晰地符合“学生将修完生物学系的所有课程”。