2.3.1问题
如果你想计算两个集合之间的差异。例如,你想找出Andrew选取而Cindy没有选取的课程。这个问题的一个变异是,你也想从其它所有的集合并集中减去一个集合。换句话说,Cindy想通过列出所有她的朋友已经完成的而她还没有完成的学期报告找出她的朋友是怎么做的。
2.3.2解决方案
在这个演示中有两个问题。第一个是从一个集合中简单地减去另一个。第二个是从其它所有集合的并集中减去一个集合。两个问题的解决方案实际上是同一个,因为多个集合的并集只是一个更大的集合。
2.3.2.1从一个集合中减去另一个
考虑一个问题:找出Andrew已经完成而Cindy没有完成的学期报告。这个问题包括两个集合:Andrew已经完成的报告和Cindy已经完成的报告。下面的查询返回这两个集合间的差集:
SELECT
s.CourseId, s.TermPaper
FROM
Students s
WHERE
s.StudentName
=
'
Andrew
'
AND
NOT
EXISTS
(
SELECT
*
FROM
Students s1
WHERE
s1.CourseId
=
s.CourseId
AND
s1.TermPaper
=
s.TermPaper
AND
s1.StudentName
=
'
Cindy
'
)
查询的结果:
CourseId TermPaper
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
--
------- -----------
ACCN101
4
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
ACCN101
3
2.3.2.2从其它所有集合的的并集中减去一个集合
这个问题的一个微小的变化是从其它所有集合的并集中减去一个特定的集合。这就引出了我们的问题的第二部分—找出Cindy的朋友完成的Cindy未完成的学期报告。下面的查询完成这个功能:
SELECT
s.StudentName, s.CourseId, s.TermPaper
FROM
Students s
WHERE
s.StudentName
<>
'
Cindy
'
AND
NOT
EXISTS
(
SELECT
*
FROM
Students s1
WHERE
s.CourseId
=
s1.CourseId
AND
s.TermPaper
=
s1.TermPaper
AND
s1.StudentName
=
'
Cindy
'
)
查询返回以下结果:
StudentName CourseId TermPaper
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
--
----------- --------- -----------
Andrew ACCN101
4
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
Andrew ACCN101
3
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
Bert ACCN101
3
现在我们知道学校所有的人,只有Andrew和Bert完成了Cindy没有完成的学期报告。
2.3.3讨论
找出两个集合之间的不同需要使用子查询,它通常对CPU和内存消耗是一项昂贵的任务。解决这种问题的关键在于定义解决方案包括的集合。例如,Cindy完成的学期报告集合是在这个示例中讨论的问题中都有的集合。一旦你定义了你的集合,你就能使用带有NOT EXISTS的SELECT语句返回两个集合间的差集。
2.3.3.1 从一个集合中减去另一个集合
第一个SELECT语句,从Andrew写的学期报告集合中减去Cindy写的学期报告。外面的SELECT语句返回所有Andrew写的学期报告。NOT EXISTS修改了那个查询返回的结果,所以它们可以排除所有Cindy完成的学期报告,内部的SELECT语句定义了Cindy完成的报告。整个查询返回的结果是Andrew写了,但Cindy没写的报告。
2.3.3.2 从其它所有的集合中减去一个集合
第二个SELECT语句从其它所有的集合中减去Cindy写的学期报告。解决这个问题的方法与上一个问题大致相同。唯一的不同是外面的SELECT语句定义的集合包括所有学生的学期报告而不是Cindy的。
第二个SELECT语句返回的结果是所有其它学生上交的学期报告列表,而不是Cindy的。因为多个学生可以上交同样的学期报告,在结果中包括学生姓名使得结果变得有意义。Cindy想要知道 谁提交了她没有提交的报告。
2.3.3.3 从一个集合中减去多个集合
第二个查询实际上导致了第三种计算集合差集的解决方案—从一个集合中减去多个集合。假设你想要Andrew写的但其他学生没有写的报告列表,你可以使用下列查询生成结果:
SELECT
s.CourseId, s.TermPaper
FROM
Students s
WHERE
s.StudentName
=
'
Andrew
'
AND
NOT
EXISTS
(
SELECT
*
FROM
Students s1
WHERE
s1.CourseId
=
s.CourseId
AND
s1.TermPaper
=
s.TermPaper
AND
s1.StudentName
<>
'
Andrew
'
)
在这个例子中,外面的SELECT语句返回Andrew写的报告列表。这是起点,子查询定义了其他学生完成的报告列表。两个集合进行了相减,结果就是只有Andrew提交的学期报告列表。
如果你想计算两个集合之间的差异。例如,你想找出Andrew选取而Cindy没有选取的课程。这个问题的一个变异是,你也想从其它所有的集合并集中减去一个集合。换句话说,Cindy想通过列出所有她的朋友已经完成的而她还没有完成的学期报告找出她的朋友是怎么做的。
2.3.2解决方案
在这个演示中有两个问题。第一个是从一个集合中简单地减去另一个。第二个是从其它所有集合的并集中减去一个集合。两个问题的解决方案实际上是同一个,因为多个集合的并集只是一个更大的集合。
2.3.2.1从一个集合中减去另一个
考虑一个问题:找出Andrew已经完成而Cindy没有完成的学期报告。这个问题包括两个集合:Andrew已经完成的报告和Cindy已经完成的报告。下面的查询返回这两个集合间的差集:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
查询的结果:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
2.3.2.2从其它所有集合的的并集中减去一个集合
这个问题的一个微小的变化是从其它所有集合的并集中减去一个特定的集合。这就引出了我们的问题的第二部分—找出Cindy的朋友完成的Cindy未完成的学期报告。下面的查询完成这个功能:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
查询返回以下结果:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
现在我们知道学校所有的人,只有Andrew和Bert完成了Cindy没有完成的学期报告。
2.3.3讨论
找出两个集合之间的不同需要使用子查询,它通常对CPU和内存消耗是一项昂贵的任务。解决这种问题的关键在于定义解决方案包括的集合。例如,Cindy完成的学期报告集合是在这个示例中讨论的问题中都有的集合。一旦你定义了你的集合,你就能使用带有NOT EXISTS的SELECT语句返回两个集合间的差集。
2.3.3.1 从一个集合中减去另一个集合
第一个SELECT语句,从Andrew写的学期报告集合中减去Cindy写的学期报告。外面的SELECT语句返回所有Andrew写的学期报告。NOT EXISTS修改了那个查询返回的结果,所以它们可以排除所有Cindy完成的学期报告,内部的SELECT语句定义了Cindy完成的报告。整个查询返回的结果是Andrew写了,但Cindy没写的报告。
2.3.3.2 从其它所有的集合中减去一个集合
第二个SELECT语句从其它所有的集合中减去Cindy写的学期报告。解决这个问题的方法与上一个问题大致相同。唯一的不同是外面的SELECT语句定义的集合包括所有学生的学期报告而不是Cindy的。
第二个SELECT语句返回的结果是所有其它学生上交的学期报告列表,而不是Cindy的。因为多个学生可以上交同样的学期报告,在结果中包括学生姓名使得结果变得有意义。Cindy想要知道 谁提交了她没有提交的报告。
2.3.3.3 从一个集合中减去多个集合
第二个查询实际上导致了第三种计算集合差集的解决方案—从一个集合中减去多个集合。假设你想要Andrew写的但其他学生没有写的报告列表,你可以使用下列查询生成结果:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
在这个例子中,外面的SELECT语句返回Andrew写的报告列表。这是起点,子查询定义了其他学生完成的报告列表。两个集合进行了相减,结果就是只有Andrew提交的学期报告列表。