我想用我的头来理解使用NOT EXISTS进行除法的工作。我知道如何不使用Exist编写SQL查询。但是不知何故,我错过了这种查询的评估方式。任何解释和帮助将不胜感激。
我的查询是:输入所有课程的学生姓名。
student
表
SID SName
S1 Amy
S2 Tracy
course
表
CID coursename
C1 computer
C2 Biology
enrolled
表。密钥是SID和CID
SID CID
S1 C1
S1 C2
S2 C1
我的SQL查询如下:
SELECT s.SName
FROM student s
WHERE NOT EXISTS
(SELECT CID from course c
WHERE NOT EXISTS
(SELECT S.SID
FROM enrolled E
WHERE S.SID=E.SID AND
C.CID=E.CID));
我的理解是:
对于S1: 内部查询将获取 -首先使用C1,然后检查S1是否已注册C1。就我们而言。他是。它 将返回假 -然后它将检查C2并再次为假。
是这样吗?我现在很困惑。
答案 0 :(得分:1)
SQL似乎正常。
回答您的实际问题:“但是不知何故,我不知道这种查询的评估方式。”
概念上 发生的情况是,最外层的[FROM STUDENT AS S]一次覆盖所有学生,每次保留“当前”属性值”,以供进一步参考。
然后最外面的WHERE NOT EXISTS一步一步扫描所有课程[SELECT FROM COURSE],从而再次将“当前”行中的属性值保留在上下文中以供进一步参考[因此,我们现在都拥有一个“当前”学生行以及“当前”课程行]。
然后,最里面的“不存在”去检查是否有根据上下文提供给学生的课程以及根据上下文提供的课程。如果没有,则存在一门该学生未被注册的课程,这样特定的学生就不会学习所有课程。
我在概念上强调了 ,因为在计算中使用的实际数据访问策略可能完全不同,因此我将再次强调它。 。但是结果必须像按照说明的那样进行。
编辑
使用更正式的逻辑术语:
查询要求
{学生|对于所有课程:ENROLLED(SID,CID)}
在ENROLLED()中,SID绑定到受限制的STUDENT集,而CID绑定到FORALL的主题。
(也许作为练习来检查这几乎是问题陈述)。
否定FORALL,与
相同{学生|不存在的课程:未注册(SID,CID)}
并且NOT ENROLLED()条件为true时,所关注的SID,CID行不存在(即,不存在)。再次作为练习,检查一下这实际上是SQL解决方案的原因。
答案 1 :(得分:0)
也许其他方法更容易理解。
这是您的SQLite示例:
PRAGMA foreign_keys = ON;
create table student (
SID text primary key,
SName text
);
insert into student (SID, SName) values ('S1', 'Amy');
insert into student (SID, SName) values ('S2', 'Tracy');
create table course (
CID text primary key,
coursename text
);
insert into course (CID, coursename) values ('C1', 'computer');
insert into course (CID, coursename) values ('C2', 'Biology');
create table enrolled (
SID text references student (SID),
CID text references course (CID),
primary key (SID, CID)
);
insert into enrolled (SID, CID) values ('S1', 'C1');
insert into enrolled (SID, CID) values ('S1', 'C2');
insert into enrolled (SID, CID) values ('S2', 'C1');
您想要那些没有错过课程的学生。 SID
和CID
是enrolled
的主键。这意味着一个学生不能两次参加同一门课程。这意味着您只需要计算课程数即可。如果每个学生的课程总数与所有课程的总数相同,则该学生拥有所有课程。
这是所有课程的数量:
select count(*) from course;
这是每个学生的课程数量:
select count(SName) n, SName from student s
left join enrolled e on s.SID = e.SID
group by SName;
这是您正在寻找的学生列表:
select SName from (
select count(SName) n, SName from student s
left join enrolled e on s.SID = e.SID
group by SName)
where n = (select count(*) from course);