SQL——查询和1002号的同学学习的课程完全相同的其他同学的学号和姓名

  今天做sql题,看到这个题目后,就感觉完全相同这个限定很是特别,完全相同,意思显然是:1、选课数目相同,2、选择的课每个都相同。然后书上答案看着不对就去搜了搜,果真各有各的说法,看了几个博客,自己总结了一番,最终还是选择code更直观。

  首先表结构只有一个:sc(sno,cno,grade)。表内数据如图,只有1001和1002是完全一样的。

note:下面给的sql语句为了能有1002方便对比,我没有加上其他同学条件,这个很简单,and 一个条件就够了。 

错误答案1:

select sno
from sc where cno in(
    select cno from sc where sno='1002')
group by sno
having count(*)=(
    select count(*) from sc where sno='1002');

//错误结果:
+------+
| sno  |
+------+
| 1001 |
| 1002 |
| 1003 |
+------+
3 rows in set

  两个子查询很简单,一个是找到学号为1002的同学所选的所有课程,一个是1002同学所选的课程数。

  首先理解的前提是,我们要知道sql的执行顺序:where子句是在group by ... having ...子句前执行的!group by子句是对where选择之后的元组有效,而不是对原来的整个表有效!!!这一点很多同学是完全没有注意过的。

  然后这个语句的意思就是,1、先子查询中找到了1002学生选的所有课,2、再从所有选课记录中找到选择了这些课的行,3、再根据学号分组,4、看每个学号的选课的个数是否和1002一样。

  这里的错误出在了2上面,找出了选择了这些课的行,但是选择其他课的行就被忽略了,所以1003能被选出来。1003选择了1,2,3课,多选的3被忽略掉了。

正确答案:

select sc1.sno
from (
    select sno
    from sc
    group by sno
    having count(*)=(
        select count(*) from sc where sno='1002')) sc1, sc
where sc1.sno=sc.sno and cno in(
    select cno from sc where sno='1002')
group by sc.sno
having count(*)=(
    select count(*) from sc where sno='1002');

//答案结果
+------+
| sno  |
+------+
| 1001 |
| 1002 |
+------+
2 rows in set

  这里是:1、先在子查询找到1002所选的课数,2、找出选课数相等的学生学号并命名法新表sc1,3、sc1和sc连接后,可以排除掉所有选课数目不等于1002的学生的选课记录,4、重复上个答案的1、2,5、重复上个答案的3、4操作,得出答案。

  note:网上有的答案是只有1、2、3、4,没有了5的,这样会造成的结果是1004也会被选出来,因为少了一步条件判断。

正确答案2:

select sno
from sc
where sno not in(
    select sno from sc where cno not in(
        select cno from sc where sno='1002'))
group by sno
having count(*)=(
    select count(*) from sc where sno='1002');

  这是一个让人感觉优秀的代码,not in双重否定看起来就让人觉得眼前一亮!出处在这里

  思路: 1、子查询找出1002同学选的所有课,2、not in找出选了这些课以外的其他课的同学,3、再not in选择非2中选出的同学,及只选了1002所选的那些课的同学,4、对这些同学group by后判断选课数量是否一样

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值