查询选修了超过了4门课的学生和姓名。由这个来引出话题。我一开始就是这样写的:
select tb_student.Sno,Sname
from tb_student,tb_SC
where tb_Student.Sno=tb_SC.Sno
group by tb_student.Sno
having count(*)>=4;
然后就报了这样的错误:
后来在东南大学的一个数据库视频上面看到,自己b站由收藏。老师把这个讲清楚了。我现在记录下来,以便之后复习。
首先我们知道,group by是用来将我们前面得到的结果集进行分组处理。那么,你的结果集就变成了一个一个组。就像我下面画的这个图一样。
那么现在来看,你的select子句上面就是关于这整个组的操作,上面的图是按照Sno来分组的,所以所以每一个组来说,Sno是他们的共同值,也就是说,Sno对于每一个组来说,其值是单一的。但是对于Cno来说,你要一个select Cno对于一个组而言,那么是不是就无法形成一个表格出现了。如果硬要出现,就会使这样子:
所以,SQL就在group by上面做了文法规定(文法,好高级。哈哈哈,应该就是语法吧),SQL在文法上要求在slelect和having上出现的属性必须是分组属性集的一个子集
为了达到这个目的,设计DBMS的开发者也是伤透了脑筋。这里老师在视频里说了,我就不提了,最后总结就是:
数据库设计的时候,程序员并不知道将来这个数据库会被用来做什么,所以,他不可能从逻辑上来检查你的select,having上出现的语句是不是分组属性的一个子集。所以,最简单的方法就是看你的select,having上出现的属性在group by上出现过。出现过,就通过编译,否则不会。
最后提一点,你之前都不知道having上的属性对于group by分组也是单一的,以后也得记得了。
最后正确答案是:
select tb_student.Sno,Sname
from tb_student,tb_SC
where tb_Student.Sno=tb_SC.Sno
group by tb_student.Sno,Sname
having count(*)>=4;