Bootstrap

【SQL server】查询练习题

 

 

☀ 52道关于查询的典型练习题

 

☀ 包括完整的建库、建表代码以及数据

 

-- 创建数据库
create database teachingInfo
on
(
	name = teaching,
	filename = 'D:\DataBase\teaching.mdf',
	size = 8MB,
	maxsize = 100MB,
	filegrowth = 64MB
)
log on 
(
	name = teaching_log,
	filename = 'D:\DataBase\teaching_log.log',
	size = 8MB,
	maxsize = 100MB,
	filegrowth = 64MB
)


-- 建表

--创建student表
create table student
(
	sno		int primary key identity(1, 1),
	sname	nvarchar(10) not null,
	ssex	nchar(1) not null,
	birthday date not null,
	en_time  date not null,
	specialty nvarchar(10) not null,
	grade tinyint check(grade>=1 and grade<=4)
)
-- 创建course表
create table course
(
	cno		int primary key identity(1, 1),
	cname	nvarchar(10) not null,
	classhour int not null,
	credit tinyint not null
)
-- 创建scoreinfo表
create table scoreinfo
(
	sno		int,
	cno		int,
	score	decimal(4, 1) not null,
	constraint pk_sc primary key(sno, cno),
	constraint lo_li foreign key(sno) references student(sno),
	constraint li_lo foreign key(cno) references course(cno)
)


-- 插入数据

-- 给student表插入数据
insert into student(sname, ssex, birthday, en_time, specialty, grade)
values
('loli1', '女', '2010-06-21'	, '2018-09-01', '网络工程', 2),
('loli2', '男', '2011-02-01'	, '2019-06-01', '网络工程', 1),
('loli3', '女', '2010-03-21'	, '2018-09-01', '网络工程', 2),
('loli4', '男', '2012-06-23'	, '2016-04-01', '网络工程', 4),
('loli5', '女', '2009-04-17'	, '2018-05-01', '网络工程', 2),
('loli6', '女', '2009-04-17'	, '2018-05-01', '计算机', 2),
('loli7', '女', '2009-04-17'	, '2018-05-01', '计算机', 2),
('loli8', '男', '2009-04-17'	, '2018-05-01', '计算机', 4)

-- 给course表插入数据
insert into course(cname, classhour, credit)
values
('C++', 3, 4), ('English', 4, 5), ('操作系统', 5, 6)

-- 给scoreinfo表插入数据
insert into scoreinfo
values
(3, 1, 90), (3, 2, 88), (3, 3, 99),
(4, 1, 56), (4, 2, 78), (4, 3, 49),
(5, 1, 80), (5, 2, 88), (5, 3, 89),
(6, 1, 30), (6, 2, 45), (6, 3, 45),
(7, 1, 76), (7, 2, 81), (7, 3, 78)




-- 查询


--1.查询teaching数据库中学生的姓名、性别和专业
select sname, ssex, specialty
from student


--2.查询teching库中course的所有记录
select * from course


--3.查询teaching库中student表的专业名称,滤掉重复行
select distinct specialty from student


--4.查询teaching库中course表的前三行信息
select top 3 * from course


--5.查询course表前59%行的信息(之后的题目都省略了“teaching库中”)
select top 50 percent * from course		
--☀分析:前面几个题注意关键字的顺序: select distinct top n(percent) * form Table1


--6.查询student表中所有学生的学号、姓名,结果,并指定列名为“学号”,“姓名”
select sno as 学号, sname as 姓名		--(加不加'单引号'都行)
from student
--或
select sno 学号, sname 姓名
from student
--或
select 学号 = sno, 姓名 = sname
from student


--7.查询scoreInfo表,按150分制计算成绩
select sno, cno, score * 1.5			--☀分析:可以对查询结果进行计算处理
from scoreinfo	


--8.查询scoreInfo表中成绩大于60的学生的学号、课程号、成绩
select sno, cno, score
from scoreinfo
where score > 60


--9.查询网络工程专业的男生的信息
select * from student
where specialty = '网络工程' and ssex = '男'


--10.查询是网络工程专业的,或,是男生,的学生的信息
select * from student 
where specialty = '网络工程' or ssex = '男'


--11.查询成绩在80~90之间的学生的学号、课程号、成绩
select sno, cno, score
from scoreinfo
where score between 80 and 90


--12.查询成绩不在80~90之间的学生的学号、课程号、成绩
select sno, cno, score
from scoreinfo
where score not between 80 and 90		--☀分析:不仅存在not in, 也存在not between


--13.查询网络工程专业和通信工程专业的学生的姓名、学号、专业
select sname, sno, specialty
from student 
where specialty in ('网络工程', '通信工程')


--14.没有题目,复习一下模糊查询:
-- % 零或多个任意字符;_ 一个任意字符;[ace] 一个范围内的任意字符;[^mvp] 一个不再范围内的任意字符


--15.查询所有姓张的学生的信息
select * from student
where sname like '张%'


--16.查询所有成绩为不空值的学生的学号,课程号,成绩
select sno, cno, score
from scoreinfo
where score is not null					--☀分析:不存在 = null 这种写法,正确写法是 is null


--17.从student表中查询所有网络工程和通信工程的女生的信息
select * from student
where (specialty in ('网络工程','通信工程')) and ssex = '女'


--18.查询scoreInfo表中成绩额的平均值,平均值显示列标题为“平均成绩”
select AVG(score) as '平均成绩'
from scoreinfo


--19.从student表中查询专业的种类个数
select count(distinct specialty)		--☀分析:聚合函数中使用distinct是允许的
from student


--20.查询201810223016号学生的平均成绩和最高成绩
select AVG(score), MAX(score)
from scoreinfo where sno = 201810223016


--21.查询男生和女生的个数
select ssex, count(*)					--☀分析:ssex是分组依据,所以可以select
from student							-- 另外,count是每组一个的,注意理解
group by ssex


--22.在scoreInfo表中查询选修了两门及以上课程的学生学号和选课数
select sno, count(*)
from scoreinfo
group by sno having count(*)>=2			--☀分析:having是根据分组查询后的结果进行再筛选,一般跟聚合函数


--23.查询scoreInfo表,求被选修的各门课程的平均成绩和选修该课程的人数,以及所有课程的总平均成绩和总选修人数
select cno, AVG(score), COUNT(*)
from scoreinfo 
group by cno with cube


--24.查询student表,统计各专业男生、女生人数及每个专业学生人数,男生总人数、女生总人数,以及所有学生总人数
select specialty, ssex, grade, count(*)
from student
group by specialty, ssex,grade with cube
--(★重难点)
-- cube用在group by之后,作用为:不仅根据分组依据进行分组统计,再根据分组依据的所有子集(包括空集)进行分组统计
-- demo: 分组依据为 a, b, c,则结果集多了很多行统计结果分组依据分别为(a, b, c)(a, b)(a, c)(a, c)(a)(b)(c)(空)


--25.统计每个专业的男女生人数,每个专业的总人数和所有学生的总人数
select specialty, ssex, count(*)
from student
group by specialty, ssex with rollup
--(★重难点)
-- rollup用在group by之后,作用为:和cube类似,但不是所有子集,而是从最低级别的分组依据开头的子集和空集
-- demo: 分组依据为 a, b, c,则结果集多了很多行统计结果分组依据分别为(a, b, c)(a, b)(a)(空)


--26.查询每个学生的姓名、课程号、成绩
select sname, cno, score
from scoreinfo												
inner join student on student.sno = scoreinfo.sno	--☀分析:简单的内连接


--27.查询网络工程专业的学生所选的每门课的平均分
select cno, AVG(score)
from scoreinfo
inner join student on student.sno = scoreinfo.sno	
where specialty = '网络工程'
group by cno								--☀技巧:需要select的是cno,那么分组依据就是cno


--28.查询同名学生的信息				
select *
from student a
inner join student b on a.sname = b.sname and a.sno != b.sno
--★ 分析:先弄清楚题意的关键,同名学生就是"姓名相同,而学号不同"
-- 另外,此题是内连接时,注意给表取别名,使其在逻辑上成为两个表


--29.查询每个学生及其选修课程的成绩情况(含未选课的学生信息)
select student.*, cno, score
from scoreinfo 
right join student on student.sno = scoreinfo.sno	
--☀分析:左/右外连接 left/right join


--30.查询每个学生及其选修课程的情况(含未选课的学生信息及未被选修的课程信息)
select student.*, course.*
from scoreinfo
full join student on student.sno = scoreinfo.sno
full join course on course.cno = scoreinfo.cno		
--☀分析:全外连接 full join 


-- 31.查询成绩在75分以上的学生的学号、姓名,选修课的课程号、成绩
select student.sno, sname, course.cno, score
from scoreinfo
inner join student on student.sno = scoreinfo.sno
inner join course on course.cno = scoreinfo.cno
where score > 75									--☀分析:最经典的三表内连接


-- 32.查询所有学生可能的选课情况
select sname, cname
from student 
cross join course									--☀分析:笛卡尔积 cross join,也称为交叉连接


--33.查询与loli1同一个专业的学生的学号、姓名
select sno, sname									--☀分析:典型的子查询:需要先查出loli1的专业
from student
where specialty = (select specialty from student where sname = 'loli1')


--34.查询课程号为3的考试成绩比loli2高的学生的学号和姓名
select student.sno, sname 
from student
inner join scoreinfo on student.sno = scoreinfo.sno
where cno = 3 
and score > (select score from scoreinfo where cno = 3 and sno = (select sno from student where sname = 'loli2'))
--★算是一个难题:嵌套了三个select而且需要表的内连接
--思路:
--1.找出课程号为3,姓名为loli2的学生的成绩(这一步可以内连接,也可以两个select嵌套【如上】)
--2.内连接,把上面查的那个成绩作为用在此次查询中(典型的子查询)


--35.查询网络工程专业年龄最大的学生的姓名、学号
select sname, sno
from student
where specialty = '网络工程'
and birthday <= all(select birthday from student where specialty = '网络工程')


--36.查询与任何一个网络工程专业同学同龄的学生的信息
select *
from student
where birthday = any(select birthday from student where specialty = '网络工程')
--★上面的两道题使用看新的知识:使用all, any(some)的子查询
-- 顾名思义,all是指“所有值”,any(some)是指“只要有一个值”;弄清其使用的场景,真的可以省很多事


--37.查询选修了1号课程的学生姓名和所在专业
select sname, specialty
from student										
where sno in (select sno from scoreinfo where cno = 1)	--☀分析:内联表当然也可以做,但使用in是精妙的思路


--38.查询有两个以上学生平均成绩超过80分的班级(专业+年级)
select specialty, grade 
from student
where sno in (select sno from scoreinfo group by sno having avg(score) > 80)
group by specialty, grade having count(*) > 2
--★是一个难题:本质是子查询
--思路:
--1.先select出平均成绩大于80的所有学生的学号:select sno from scoreinfo group by sno having avg(score) > 80
--2.上面子查询的结果用在了主查询中(in的使用)
--3.子查询和主查询都用到了having(是关键点也是难点)
--★ 关于group by...having结构,明白一点问题就变得简单了:分组依据就是select后紧跟的要查询的列名


-- 上面讲的都是【无关子查询】———— 子查询只用一次,也只执行一次
-- 下面讲的是【相关子查询】———— 子查询重复执行,外部查询每遍历一行,子查询就执行一次
-- 【相关子查询】有个极为显著的特点:就是因为子查询需要用到外部查询的表(“相关”),因此【外部查询用的表和内部查询用的表有联系且都有别名!!!】


--39.查询成绩比该课的平均成绩低的学生的学号、课程号、成绩
select sno, cno, score
from scoreinfo as a
where score < (select avg(score) from scoreinfo as b where a.cno = b.cno)


--40.查询两门及以上课程的成绩在80分以上(包括80)的学生的学号、姓名、年级、专业
select sno, sname, grade, specialty
from student
where sno in (select sno from scoreinfo where score >= 80 group by sno having count(*) >= 2)
-- 使用【相关子查询】的方法:
select sno, sname, grade, specialty
from student s
where (select count(*) from scoreinfo sc where s.sno = sc.sno and score >= 80) >= 2


--41.查询所有选修了1号课程的学生姓名
select s.sname
from student s
where exists (select * from scoreinfo sc where s.sno = sc.sno and cno = 1)
--★ 带有exists的子查询也是一种特殊的【相关子查询】,也称为“存在性测试”


--42.查询选修了课程1的学生和课程3的学生的姓名和课程号
select cno = 1, sname
from student
where sno in (select sno from scoreinfo where cno = 1)
union
select cno = 3, sname
from student
where sno in (select sno from scoreinfo where cno = 3)	--☀分析:典型的union联合查询
--★ 我们还有一个发现!内联表的功能,使用无关子查询也可以实现!!!


--43.查询网络工程专业没有选修C++的学生的学号和姓名
select sno, sname
from student
where sno not in (select sno from scoreinfo where cno = (select cno from course where cname = 'C++'))
and specialty = '网络工程'
--★ 这再一次印证了:这题可以用三表内联的方法,就同样可以使用子查询的多层嵌套,且思路都是正向的,非常清晰
-- 画蛇添足,使用except差集(也属于联合查询)
select sno, sname from student where specialty = '网络工程'
except
select sno, sname
from student
where sno in (select sno from scoreinfo where cno = (select cno from course where cname = 'C++')) and specialty = '网络工程'


--44.查询既选修了课程1又选修了课程3的学生的学号
select sno from scoreinfo where cno = 1
intersect
select sno from scoreinfo where cno = 3			--☀分析:交集(intersect)的使用——这也是一种【联合查询】


--45.查询女学生的姓名和专业,并按姓名升序排列
select sname, specialty
from student
where ssex = '女'
order by sname asc


--46.查询scoreInfo表中学生的成绩和学号,并按成绩降序排列
select score, sno 
from scoreinfo
order by score desc


--47.查询学生的成绩和学号,并按成绩降序排列,若成绩相同,则按学号升序排列
select score, sno
from scoreinfo
order by score desc, sno asc


--48.查询平均成绩最高的前三名
select top 3 sno
from scoreinfo
group by sno
order by AVG(score) desc	--☀分析:这里有一个重点:当我们想用top取前三名时,表应该是asc还是desc呢?是降序desc


--49.将查询的学生姓名、学号、课程名、成绩的相关数据存放在一个新表(成绩单)中
select sname, student.sno, cname, score into 成绩单						-- 注意此处的新表名(成绩单)不能加单引号
from student, course, scoreinfo
where student.sno = scoreinfo.sno and course.cno = scoreinfo.cno
--★ 这题无疑考察的是快速备份
--另外,我们也认识到,我们并不需要进行表的连接,就通过这种写法实现了多表连接的效果


--50.有一个已存在的scoreInfo表的副本空表,将scoreInfo中成绩大于80的数据加到副本成绩表中
insert into 成绩表
select * from scoreinfo
where score > 80			--☀分析:固定写法,记住就行


--51.将201810223016号学生的操作系统课的成绩改为90分
update scoreinfo
set score = 90
where sno = '201810223016'
and cno = (select cno from course where cname = '操作系统')


--52.将大二的网络工程专业的loli1选修的2号课程成绩改为99
update scoreinfo
set score = 99
where cno = 2
and sno = (select sno from student where sname = 'loli1' and grade = 2 and specialty = '网络工程')

--★ 最后的两道题应该比较明了:就是select语句在update语句中的使用
-- 思路:想要修改成绩需要精准定位到那一行,这需要两个主键sno和cno(只是主键值没有直接给出,需要用select查询一下而已)

 

 
 

本文的练习题目均改编自《 数据库原理与应用教程 》北京:清华大学出版社

;