SQL题目,求高手帮忙100分。

哎,说起来这数据库设计啊,我之前就踩过坑。
记得那年我在一个学校项目里负责数据库设计,那时候我就设计了这么一套三表结构,学生表、课程表、选课表,看起来挺简单的。
结果呢,问题就来了。

有一次,学校要统计一下学号为1 2 3 的那个学生的选课情况,我就写了这么一个SQL查询:
sql SELECT S.SNAME AS 姓名, C.CNAME AS 课程名, SC.SCORE AS 分数 FROM S, C, SC WHERE S.SNO = SC.SNO AND C.CNO = SC.CNO AND S.SNO = '1 2 3 '
这个查询其实没问题,但是运行的时候,系统突然卡住了,反应特别慢。
我一看,原来是因为学生表里学号1 2 3 那个学生选了太多课程,导致这个查询涉及到大量的数据,系统处理起来很吃力。

再有一次,有个老师让我帮忙查一下课程号为abc的课程的学生及成绩,成绩还要按从高到低的顺序排列。
我就写了这个查询:
sql SELECT C.CNAME AS 课程名, S.SNAME AS 姓名, SC.SCORE AS 分数 FROM S, C, SC WHERE S.SNO = SC.SNO AND C.CNO = SC.CNO AND C.CNO = 'abc' ORDER BY SC.SCORE DESC
这个查询当时用的时候还挺顺的,但是后来有一次课程abc突然取消了,我直接去删除课程表中的记录,结果发现选课表里的对应记录没有一起删除。
原来是我忘记加上删除课程时同时删除选课表记录的约束了。

所以啊,数据库设计看似简单,但细节得注意到位。
这块儿我就得提醒你,设计数据库表的时候,一定要考虑到数据的增删改查,还有可能的异常情况。
别像我以前那样,只顾着写查询,忽略了约束和索引这些重要的东西。

SQL语句:查询各班成绩前3的同学姓名

说白了,用ROW_NUMBER函数分班级取前三名是SQL里最直接的办法。
这玩意儿特别适合做排名截取的场景,比如去年我们跑的那个活动,得按区域取销量前五,用这个函数秒秒钟搞定。

先说最重要的,ROW_NUMBER是按分区(PARTITION BY)内部顺序排序的,所以先按"一年一班""一年二班"分开,然后在每个班级里按分数降序排。
去年跑项目时我差点忘了加PARTITION BY,结果所有数据混在一起排,说实话挺坑的。
另外一点,排名是连续的,哪怕两个班级前三名分数一样,也会被分到不同排名。
还有个细节挺关键的,ORDER BY后面加score降序,否则默认是升序,这会导致第一名是分数最低的那个,这个点很多人没注意。

我一开始也以为分完排名就能直接用,后来发现不对,还得在外层查询加WHERE排名<=3 ,不然会把所有数据都拉出来。
等等,还有个事,ORDER BY里除了score,还可以加name啥的,比如要按分数排但同分按姓名排,就写成ORDER BY score DESC, name ASC。

建议你在用ROW_NUMBER前,先在本地跑几条数据看效果,特别是分区字段和排序字段选错,结果会很诡异。
你觉得用这个函数处理动态排名场景怎么样?

如何用SQL语句实现关系的三类完整性

哈,数据库表设计这事儿,我给你捋捋。

上周有个客人问我这事儿,他搞不清实体完整性和参照完整性怎么搞。
我直接给他举了个例子,你看行不行。

第一段 CREATE TABLE Student(Sno CHAR(9 ) PRIMARY KEY, ...) 这块,Sno 是主键,这没问题,就是 Sname CHAR(2 0) UNIQUE 这部分。
你确定学生名字必须得全世界独一无二吗?我上次在杭州搞一个学校系统,发现就有重名的,最后把 UNIQUE 去掉了,改用学号加名字组合查询。
这个 Ssex CHAR(2 ) 默认值是 男,这倒是常见的。

第二段 课程信息表c 和 学生选课表sc 这块,参照完整性搞得挺对的。
cno 是 c 表的主键,sc 表里 sno 和 cno 是外键,指向 student 和 c 表的 sno 和 cno。
不过 CREATE TABLE sc(......constraint fk foreignkey(sno,cno) references student(sno) references c(cno)) 这句写错了,应该是 references student(sno) 指向 student 表的 sno,references c(cno) 指向 c 表的 cno。
你这写法 references student(sno) references c(cno) 会报错的,数据库会懵的。

第三段 CREATE TABLE student(Sno CHAR(9 ) PRIMARY KEY, Sname CHAR(2 0) UNIQUE, Ssex CHAR(2 ) check(sexin('男','女')) default '男') 这块,check(sexin('男','女')) 是对的,确保性别只能是男或女。
default '男' 也能接受。
不过 Sname CHAR(2 0) UNIQUE 还是那个问题,重名不重名你试试就知道。

我踩过的坑是 UNIQUE 加得太多,搞得查询都慢了。
后来发现 Sname 加 Sno 组合唯一就行。
你看看你们这需求,真的需要 Sname 唯一吗?
反正你看着办,这事儿吧,需求最重要。