SQL数据查询练习(MySQL)

  • 最近在帮一些同事培训学习SQL,综合网上的例子,我这边自己选了一些经典的过来做为例子然后整理了一版,以下查询基于MySQL 8
  • 表建立和数据准备
-- 老师表
CREATE TABLE `teacher` (
  `tno` varchar(20) NOT NULL,
  `tname` varchar(20) NOT NULL,
  `tsex` varchar(20) NOT NULL,
  `tbirthday` datetime DEFAULT NULL,
  `prof` varchar(20) DEFAULT NULL,
  `depart` varchar(20) NOT NULL,
  PRIMARY KEY (`tno`)
)
INSERT INTO `teacher` VALUES ('804','李诚','男','1958-12-02 00:00:00','副教授','计算机系')
,('825','王萍','女','1972-05-05 00:00:00','助教','计算机系')
,('831','刘冰','女','1977-08-14 00:00:00','助教','电子工程系')
,('856','张旭','男','1969-03-12 00:00:00','讲师','电子工程系');
-- 课程表
CREATE TABLE `course` (
  `cno` varchar(20) NOT NULL,
  `cname` varchar(20) NOT NULL,
  `tno` varchar(20) NOT NULL,
  PRIMARY KEY (`cno`)
)
INSERT INTO `course` VALUES 
('3-105','计算机导论','825'),('3-245','操作系统','804')
,('6-166','数字电路','856'),('9-888','高等数学','831');

-- 学生表
CREATE TABLE `student` (
  `sno` varchar(20) NOT NULL,
  `sname` varchar(20) NOT NULL,
  `ssex` varchar(20) NOT NULL,
  `sbirthday` datetime DEFAULT NULL,
  `class` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`sno`)
)
INSERT INTO `student` VALUES ('101','曾华','男','1977-09-01 00:00:00','95033')
,('102','匡明','男','1975-10-02 00:00:00','95031')
,('103','王丽','女','1976-01-23 00:00:00','95033')
,('104','李军','男','1975-02-10 00:00:00','95033')
,('105','王芳','女','1974-06-03 00:00:00','95031')
,('106','陆君','男','1974-06-03 00:00:00','95031')
,('107','王尼玛','男','1976-02-20 00:00:00','95033')
,('108','张全蛋','男','1975-02-10 00:00:00','95031')
,('109','赵铁柱','男','1974-06-03 00:00:00','95031')
,('110','赵英俊','女','1978-05-01 00:00:00','95033')
,('111','王二妮','女','1978-04-30 00:00:00','95033')
,('112','赵四','男','1977-03-23 00:00:00','95031')
,('113','李乔','女','1976-12-30 00:00:00','95031')
,('114','孙宾','女','1979-02-28 00:00:00','95033')
,('115','李家村','男','1978-09-13 00:00:00','95031');

--成绩表
CREATE TABLE `score` (
  `sno` varchar(20) NOT NULL,
  `cno` varchar(20) NOT NULL,
  `degree` decimal(10,0) DEFAULT NULL
)
INSERT INTO `score` VALUES ('101','3-105',91),('103','3-105',74),('105','3-105',81),('107','3-105',79),('109','3-105',76),('110','3-105',59)
,('111','3-105',95),('113','3-105',94),('115','3-105',77),('101','3-245',71),('102','3-245',93),('103','3-245',78),('106','3-245',68),('110','3-245',92),('111','3-245',89),('114','3-245',65),('115','3-245',93),('101','6-166',77)
,('102','6-166',78),('105','6-166',94),('106','6-166',94),('107','6-166',61),('110','6-166',68),('111','6-166',62),('113','6-166',86),('114','6-166',53)
,('115','6-166',60),('101','9-888',76),('103','9-888',66),('105','9-888',94),('106','9-888',59),('107','9-888',74),('108','9-888',56),('109','9-888',76)
,('112','9-888',62),('113','9-888',50),('114','9-888',77),('115','9-888',69);

  • 经典查询例子
  • 1、查询“操作系统”课程比”计算机导论“课程成绩高的学生的信息及课程分数
select s.sno,s.sname,s.ssex,s.sbirthday,s.class from student s
inner join(
	select sno
	,max(case when cname='操作系统' then degree end)os_degree
	,max(case when cname='计算机导论' then degree end)compute_degree
	from score sc inner join course c on c.cno=sc.cno
	group by sno
)b on s.sno=b.sno;
  • 2、查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩 按平均倒序,保留1位小数
select s.sno,s.sname,cast(avg(sc.degree) as decimal(10,1))avg_degree 
from student s 
inner join score sc on s.sno=sc.sno 
group by s.sno,s.sname
having avg(sc.degree)>=60
order by 3 desc;
  • 3、查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )
select s.sno,s.sname,count(*)course_cnt,sum(sc.degree)avg_degree 
from student s 
left join score sc on s.sno=sc.sno 
group by s.sno,s.sname
order by 3 desc;
  • 4、查有成绩的学生信息
select s.sno,s.sname
from student s 
where s.sno in(
	select sno from score group by sno
);
select s.sno,s.sname
from student s 
left join score sc on s.sno=sc.sno 
where sc.degree is not null
group by s.sno,s.sname;
  • 5、查询「王」姓学生的数量
select count(*)stu_cnt from student where sname like '王%'
  • 6、查询学过「王萍」老师授课的同学的信息
select s.sno,s.sname,s.ssex,s.sbirthday,s.class 
from teacher t 
inner join course c  on c.tno=t.tno
inner join score sc on c.cno=sc.cno
inner join student s on sc.sno=s.sno
where t.tname='王萍'
order by s.sno;
  • 7、查询没有学全所有课程的同学的信息;
select * from student
where sno in(
	select sno from score sc
	group by sno
	having count(*)<(select count(*) from course)
);
  • 8、查询和” 李巧 “同学学习的课程完全相同的其他同学的信息
-- 将所有人学习的课程与李同学学习的课程号一一关联。然后统计学习数量。如果数据和李同学一样那就表示一样
select * from (
   select b.sno,b.sname,ssex
   ,count(distinct b.cno )c_cnt
   from (
   	select s.sno,sc.cno,s.sname from student s 
   	inner join score sc on s.sno=sc.sno
   	where s.sname='李巧'
   )a left join(
   	select s.sno,sc.cno,s.sname,s.ssex from student s 
   	inner join score sc on s.sno=sc.sno
   	-- where s.sname!='李巧'
   )b on a.cno=b.cno
   group by b.sno,b.sname,ssex
)a
where sname!='李巧' and c_cnt=(
   	select count(distinct sc.cno) from student s 
   	inner join score sc on s.sno=sc.sno
   	where s.sname='李巧'
);
--- 方法二
-- - 假设所有人都学了和李巧一样的课程(使用笛卡尔积),然后看大家也有没有没有分数的课程,没有的话就表示一样
select 
a.sno,a.sname,a.ssex,a.sbirthday
-- ,count(case when b.degree is null then 1 end)cnt
from (
   select s.sno,s.sname,s.ssex,s.sbirthday,a.cno 
   from (
   	select sc.cno 
   	from student s 
   	inner join score sc on s.sno=sc.sno
   	where s.sname='李巧'
   )a,student s
)a left join score b on a.cno=b.cno and a.sno=b.sno
where a.sname!='李巧'
group by a.sno,a.sname,a.ssex,a.sbirthday
having count(case when b.degree is null then 1 end)=0
  • 9、查询至少有一门课与学号为” 王尼玛 “同学所学相同的同学的信息
-- 至少有一门,那就是所有学生的有分数课程no与王尼玛的课程no关联有值就表示有
select b.sno,b.sname,count(*)cnt from (
	select cno from student s 
	inner join score sc on s.sno=sc.sno 
	where s.sname='王尼玛'
)a inner join (
	select s.sno,s.sname,cno from student s 
	inner join score sc on s.sno=sc.sno 
	where s.sname!='王尼玛'
)b on a.cno=b.cno
group by  b.sno,b.sname
  • 10、查询没学过”张旭”老师讲授的任一门课程的学生姓名
--反向查询、或者也可以假设所有人都学了张老师的课。然后在查谁没有这门课的成绩
select * from student s
where s.sno not in(
	select sno 
    from score sc 
	where sc.cno in(
		select c.cno from course c 
		inner join teacher t on c.tno=t.tno and t.tname='张旭'
	)
)
  • 11、查询一门及其以上不及格课程的同学的学号,姓名及其平均成绩,保留1位小数
select s.sno,s.sname
,cast(count(distinct case when sc.degree<60 then sc.cno end) as decimal(10,1))not_pass_cnt
,cast(avg(sc.degree) as decimal(10,1))acg_degree
from student s
left join score sc on s.sno=sc.sno
group by s.sno,s.sname
having not_pass_cnt>=1
  • 12、查询各学生年纪按年份计算
select sno,sname,ssex,year(now())-year(sbirthday)sage from student
  • 13、查询1974年出生的平均成绩
select avg(sc.degree)min_degree
from student s inner join  score sc on sc.sno=s.sno 
where year(sbirthday)=1974
  • 14、查看每个学生分数最少的课程和对应的分数
select * from (
	select s.sno,s.sname,c.cname,sc.degree
	,rank() over(partition by s.sno,s.sname order by sc.degree)orderid
	from course c 
	inner join score sc on c.cno=sc.cno
	inner join student s on sc.sno=s.sno
)a
where orderid=1;
--不使用开窗函数
select a.sno,a.sname,c.cname,sc.degree 
from (
	select s.sno,s.sname
	,min(sc.degree)min_degree
	from score sc
	inner join student s on sc.sno=s.sno
	group by s.sno,s.sname
)a inner join score sc on a.min_degree=sc.degree 
inner join course c on c.cno=sc.cno
  • 15、查看每个老师的的课程的学生的分数按高低成绩排名
select c.cname,t.tname,sc.degree 
,rank() over (partition by c.cno order by sc.degree desc)rank_id
from course c
inner join score sc on c.cno=sc.cno
inner join teacher t on t.tno=c.tno;
  • 16、查询本月过生日的学生
select * from student where month(sbirthday)=month(now())
  • 17、查看接下来一个月内要过生日的学生;
--将所有学生的出生年份换算到今年然后进行比较
select * from student 
where date_add(sbirthday,interval (year(now())-year(sbirthday)) year)<=date_add(now(),interval 1 month)
and date_add(sbirthday,interval (year(now())-year(sbirthday)) year)>=curdate()
  • 18、查询所有同学的学生编号、学生姓名、选课总数、所有课程的成绩总和
select s.sno,s.sname
,count(distinct sc.cno)course_cnt,sum(sc.degree)total_degree 
from student s
left join score sc on s.sno=sc.sno
group by s.sno,s.sname
order by 1;
  • 19、查询各科成绩最高分、最低分和平均分,以如下形式显示如下
    – 课程ID 课程name 课程人数 最高分 最低分 平均分 及格率 优秀率
use school;
select  c.cno,cname
,count(distinct sc.sno)stu_cnt
,max(sc.degree)max_degree
,min(sc.degree)min_degree
,avg(sc.degree)avg_degree
,count(distinct case when sc.degree>=60 then sc.sno end)*100/count(distinct sc.sno) pass_ratio
,count(distinct case when sc.degree>=80 then sc.sno end)*100/count(distinct sc.sno) excellent_ratio
from course c 
left join score sc on c.cno=sc.cno
group by c.cno,cname
order by 3 desc 
  • 20、统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
select c.cname,c.cno,count(*)students
,cast(sum(case when degree<=100 and degree>=85 then 1 else 0 end)*100/count(*) as decimal(10,2))  '[100-85]'
,cast(sum(case when degree<85 and degree>=70 then 1 else 0 end)*100/count(*)  as decimal(10,2)) '[85-70]'
,cast(sum(case when degree<70 and degree>=60 then 1 else 0 end)*100/count(*) as decimal(10,2))  '[70-60]'
,cast(sum(case when degree<60 then 1 else 0 end)*100/count(*) as decimal(10,2)) '[60-0]'
from course c
inner join score sc on c.cno=sc.cno
group by c.cname,c.cno
  • 21、查询各科成绩前三名的记录
select * from (
 select c.cname,s.sno,s.sname,sc.degree 
 ,row_number() over(partition by c.cno order by sc.degree desc)rank_id
 from course c
 inner join score sc on c.cno=sc.cno
 inner join student s on sc.sno=s.sno
)a where rank_id<=3;

部分参考:https://blog.csdn.net/qq_41338740/article/details/81034134

你可能感兴趣的:(MySQL,数据库)