SQL Server学习笔记——多表查询

Posted Aiden_Zhao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL Server学习笔记——多表查询相关的知识,希望对你有一定的参考价值。

SQL Server学习笔记——多表查询

已知数据库中存在四个表:

  • major(专业):
  • stu(学生):
  • cou(课程):
  • sc(成绩):

连接查询

1. 等值连接

(1) 查询每个学生的信息和选修课程的信息
学生的信息在stu表中,学生的选课信息在sc表中,stu和sc表拥有共同的字段sno,查询语句为:

select stu.*, sc.* from stu, sc where stu.sno = sc.sno

查询之后的结果为:

有些学生选修了多门课程,故在查询结果中出现多次。
(2) 查询选修’20201’课程的学生姓名

select stu.sname from stu, sc where stu.sno = sc.sno and sc.cno = '20201'

查询结果为:

(3) 查询每个学生的信息和选修课程的信息、学时(多表连接)
学生的信息在stu表中,学生的选课信息在sc表中,课程的学时信息在cou表中。stu和sc表拥有共同的字段sno,sc和cou拥有共同的字段cno,故可通过两个字段将三个表相连,查询语句为:

select stu.*, sc.*, cou.ctime from stu, sc, cou where stu.sno = sc.sno and sc.cno = cou.cno

查询结果为:

2. 左外连接

(1) 查询所有学生的信息和选课信息,没有选课的学生也要显示出来
通过左连接stu表,则可显示stu中的全部信息,sc表中无对应记录的部分则输出NULL。

select stu.*, sc.* from stu left outer join sc on stu.sno = sc.sno
--等价于
select stu.*, sc.* from sc right outer join stu on stu.sno = sc.sno --右连接

:left outer join 语句后不可使用where+条件语句,应使用on代替where。
查询结果为:

(2) 查询每个专业的学生人数
① 假设每个专业都有人:

select mno, count(sno) as num from stu group by mno

查询结果为:

因为有的同学专业信息为空,则上述查询语句可优化为:

select mno, count(sno) as num from stu group by mno having mno between '1' and '4'

查询结果为:

② 假设有的专业可能没人
在查询之前,在major插入一个没有学生的专业:

insert into major values('5', '控制工程')

插入之后的major表为:

因为 ‘5 控制工程’ 是没有学生的,但要求查询所有专业的学生数量,则需要左接major表,用于显示所有的专业信息,查询语句可写为:

select major.mno, count(sno) as num from major left outer join stu on major.mno = stu.mno group by major.mno
--等价于
select major.mno, count(sno) as num from stu right outer join major on major.mno = stu.mno group by major.mno

查询结果为:

可见,专业 ‘5’ 也被统计出来,查询成功。

嵌套查询

1. 不相关嵌套查询(子查询不依赖父查询)

(1) 查询选修’20201’课程的学生姓名
① 使用上述连接查询

select sname from stu, sc where stu.sno = sc.sno and sc.cno = '20201'

② 使用不相关嵌套查询
stu和sc依靠字段sno相连,首先从sc表中查询课程为’20201’的所有学号:

select sno from sc where cno = '20201'

结果为:

接下来,则从stu表中查询上述学号(sno)对应的学生姓名(sname):

select sname from stu where sno in (select sno from sc where cno = '20201')

上述查询则为不相关嵌套查询,即子查询不依赖父查询,子查询中无连接。另外,当返回一条结果时候,可用"=",但建议同意用"in",因为返回结果的数量一般未知。

2. 相关嵌套查询(将连接放在子查询里面)

(1) 查询选修’20201’课程的学生姓名
① 连接查询和不相关嵌套查询

--连接查询
select sname from stu, sc where stu.sno = sc.sno and sc.cno = '20201'
--不相关嵌套查询
select sname from stu where sno in (select sno from sc where cno = '20201')

② 相关嵌套查询

select sanme from stu where '20201' in (select cno from sc where stu.sno = sc.sno)

查询结果为:

相关嵌套查询是子查询中引用了某张表且这张表也在子查询外部被使用到,其本质是将连接放在子查询里面。如上述查询语句,先从sc表中查询课程号,且通过sno字段将两个表连接,之后从查询结果中抽取课程号为’20201‘的对应记录输出。
(2) 查询选修’C语言’课程的学生学号

select sno from sc where 'C语言' in (select cname from cou where sc.cno = cou.cno)

查询结果为:

(3) 查询每个学生超过他平均分的课程号
首先查询一下每个学生的平均分:

select avg(grade) from sc group by sno

查询结果为:

使用相关嵌套查询每个学生超过他平均分的课程号:

select sno, cno from sc where grade > (select avg(grade) from sc group by sno having sc.sno = sc.sno)

上述语句则会报错,原因是sc.sno = sc.sno无法识别,则可对两个sc表分别起一个别名,改为:

select sno, cno from sc t1 where grade > (select avg(grade) from sc t2 group by sno having t1.sno = t2.sno)

查询结果为:

拓展:使用派生表实现上述需求:

select sno, cno from sc, (select sno, avg(grade) from sc group by sno) as avg_sc(avg_sno, avg_grade) where sc.sno = avg_sc.avg_sno and sno.grade > avg_sc.avg_grade

sql select sno, avg(grade) from sc group by sno存入一个派生表avg_sc中,avg_sc有两个字段,即学生学号和平均分,通过sno和avg_sno字段将其连接。
:这里不是真的在database中create一个新的表。

3. 带有exists的查询(涉及两个表也需要连接)

(1) 查询选修’20201’课程的学生姓名

--连接查询
select sname from stu, sc where stu.sno=sc.sno and sc.cno='20201'
--带有exists的查询
select sname from stu where exists (select * from sc where stu.sno=sc.sno and cno = '20201')

查询结果:

exists查询:每次只取一个连接,即sno,进行查询,exists不会返回具体的数据,而是返回True或者False,即sc表中有数据与当前sno对应,则返回True,否则返回False。

4. 集合查询

(1) 查询年龄是18且mno='1’的学生学号(intersect,交)

select sno from stu where age = 18 and mno = '1'
--使用intersect可写为:
select sno from stu where age = 18 intersect select sno from stu where mno = '1'

查询结果为:

(2) 查询年龄是18且mno='1’的学生学号 (except,除了)
先选出年龄是18岁的学生,再除去专业不是’1’的学生,则剩下的学生即为所查。

select sno from stu where age = 18 except select sno from stu where mno != '1'

查询结果为:

(3) 查询选修’20201’或’20203’课程的学生学号(union,并)

select distinct sno from sc where cno in ('20201', '20203')
--使用union可写为:
select sno from sc where cno = '20201' union select sno from sc where cno = '20203'

查询结果为:

以上是关于SQL Server学习笔记——多表查询的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server学习笔记——存储过程

SQL Server学习笔记——存储过程

请问:如何用sql语句来查询有多少学生选修课呢?

数据库SQL Server2012笔记——多表查询子查询分页查询用查询结果创建新表和外连接

sql server查询总分最高学生信息

SQL学习笔记_04_多表查询