SQL 双层 not exist 嵌套

很早的一个问题了,今天碰到又绕了一下。其实很简单。

关系模式:
学生(学号,姓名,系别,年龄)
课程(课程号,课程名,学时)
选读(学号,课程号,成绩)
问题:检索选读全部课程的学生姓名
select 学生.姓名 from 学生
where not exists(
select * from 课程 where not exists(
select * from 选读 where 学号=学生.学号 and 课程号=课程.课程号))

意思是
con1:这个学生不会con2。
con2:他有课没选。

下面是网上关于这件事的讨论,弄个合集防止脑子再发懵。。。
现在我们从后面的子查询向前分解:

1.所有未选过的课程的数据集:
select * from 课程 where not exists(
select * from 选读 where 课程号=课程.课程号)

2.所有没被某位学号为 @学号 的学生选过的课程的记录集(@学号学生的未选课程):
select * from 课程 where not exists(
select * from 选读 where 学号=@学号 and 课程号=课程.课程号)
请注意,多出了学号的筛选即,学号=@学号。

3.遍历每一个主查询的学号,每一个学号都按第二筛选方法筛选出:没有未选课程的学生的学号。(不包括在第查询方法查询出的“有未学课程的学号的记录集”中的记录。)
请注意:用主查询中的 学生.学号 代替了@学号。
select 学生.姓名 from 学生
where not exists(
select * from 课程 where not exists(
select * from 选读 where 学号=学生.学号 and 课程号=课程.课程号))

这已经是整个查询语句,可以看出子查询中用学生.学号替换了第2步中的 @学号,(没忘了吧,第二步求的是没有选修全部课程的某个学生)。

用上面的讲解方法不知道是不是更好理解一点。

===============

针对您最后的补充:

为什么不用
from 学生,课程,选读?

答:因为from 学生,课程,选读 也就是
SELECT * FROM 学生,课程,选读 WHERE .....条件
这样的型式只能组成内联接,而内联接我们只知道,只有三个表按联接条件都符合才会被选中,而我们要的是有不符合后面两表的的学生才符合条件,所以用内联接是不可行的。

要不然where句怎么可以调用三个关系的属性呢?

答:在SQL SERVER中规定:所有子表都是可以通过表名调用其上面任意层次的表中的字段的。所以,不是只有内联接才可以调用多个表的属性。




双重否定
从最里面开始执行

select * from 课程 where not exists(
select * from 选读 where 学号=学生.学号 and 课程号=课程.课程号))
这段是返回某学生没有选择的课程,假设返回集a

前面套个not exists的后,
当a有值,即,某学生存在没有选择的课程时,整段sql文返回null,




在这里http://www.blogjava.net/decode360/archive/2009/06/12/282804.html也有解释。
当a无值,即,某学生不存在没有选择的课程时,就是说选择了全部课程,整段sql文该学生返回姓名
  • 13
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值