MySQL50题_第21到25题

公众号:尤而小屋
作者:Peter
编辑:Peter

大家好,我是Peter

本文中介绍的是第21-25题目,主要涉及的知识点是:

  • 分组统计求和,百分比
  • 如何利用SQL实现排序
  • having使用
  • union拼接

5个题目是:

  • 查询不同老师所教不同课程平均分从高到低显示
  • 查询所有课程的成绩第2名到第3名的学生信息及该课程成绩
  • 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比
  • 查询学生的平均成绩及名次
  • 查询各科成绩前三名的记录

题目21

题目需求

查询不同老师所教不同课程平均分从高到低显示

分析过程

涉及到的表主要是

老师:Teacher

课程:Course,作为主表

成绩:Score

通过3个表的连接求出来即可

SQL实现

先找出每个老师教授了哪些课程:

select 
	c.c_name
	,t.t_name
from Course c
left join Teacher t
on c.t_id = t.t_id;

将上面的结果和成绩表连接起来:

select 
	c.c_name
	,t.t_name
	,round(avg(s.s_score),2)  score   -- 课程分组后再求均值
from Course c   -- 主表,通过两次连接
left join Teacher t
on c.t_id = t.t_id
left join Score s
on c.c_id = s.c_id
group by c.c_id   -- 课程分组
order by 3 desc;  -- 降序

题目22

题目需求

查询所有课程的成绩第2名到第3名的学生信息及该课程成绩

分析过程

成绩:Score

学生信息:Student

我们通过取出每科的第2、3名拼接起来再取出学生信息

SQL实现
自己的方法

1、课程表和成绩表连接起来,显示所有的课程和成绩信息

select 
	s.s_id
	,s.c_id
	,s.s_score
	,c.c_name
from Score s
join Course c
on s.c_id = c.c_id

2、查出全部的语文成绩

select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '语文'
order by s.s_score desc;

3、我们找出语文的第2、3的学生

select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '语文'
order by s.s_score desc
limit 1, 2;

4、同时求出语文、数学、英语的分数,并且通过union拼接

-- union连接

(select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '语文'
order by s.s_score desc
limit 1, 2)

union

(select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '数学'
order by s.s_score desc
limit 1, 2)

union
((select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '英语'
order by s.s_score desc
limit 1, 2))

5、将上面的结果学生信息表进行连接即可

好歹是实现了😭

-- 最终脚本
-- !!!!真的需要好好优化下

select
	s.s_id
	,s.s_name
	,t.c_name
	,t.s_score
from Student s
join (-- union连接

(select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '语文'
order by s.s_score desc
limit 1, 2)

union

(select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '数学'
order by s.s_score desc
limit 1, 2)

union
((select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '英语'
order by s.s_score desc
limit 1, 2)))t  -- 临时表t

on s.s_id = t.s_id

和第25题相同的方法

1、以语文为例,首先我们找出前3名的成绩(包含相同的成绩)

-- 语文
select
	a.s_id
	,a.c_id
	,a.s_score   -- 3、此时a表的成绩就是我们找的  
from Score a
join Score b
on a.c_id = b.c_id
and a.s_score <= b.s_score  -- 1、判断a的分数小于等于b的分数,要带上等号
and a.c_id="01"
group by 1,2
having count(b.s_id) <= 3  -- 2、b中的个数至少有3个,应对分数相同的情形
order by 3 desc
limit 1,2

-- 语文
select
	a.s_id
	,a.c_id
	,a.s_score   -- 3、此时a表的成绩就是我们找的  
from Score a
join Score b
on a.c_id = b.c_id
and a.s_score <= b.s_score  -- 1、判断a的分数小于等于b的分数,要带上等号
and a.c_id="01"
group by 1,2
having count(b.s_id) <= 3  -- 2、b中的个数至少有3个,应对分数相同的情形
order by 3 desc
limit 1,2;   -- 取得第2、3名

在通过数学和英语的类似操作得到2、3名的成绩,再进行拼接即可

题目23

题目需求

统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比

分析过程

课程:Course

成绩:Score

通过case语句来进行判断,count语句进行统计,sum语句进行求和

SQL实现
自己的方法

1、如何对每个成绩进行分组展示:ABCD代表相应的等级

select 
	c_id
	,s_score
	,case when s_score >= 85 and  s_score<= 100 then 'A'   -- 大小关系必须分两次写,一次写的话MySQL无法识别
		when 70 <= s_score and s_score < 85 then 'B'
		when 60 <= s_score and s_score < 70 then 'C'
		when 0 <= s_score and s_score < 60 then 'D'
		else '其他' end as 'category'
from Score s;

2、将两个表关联起来展示数据

-- 1、查看全部课程和成绩信息

select 
	s.c_id
	,c.c_name
	,s.s_score
	,case when s.s_score >= 85 and  s.s_score<= 100 then 'A'   -- 大小关系必须分两次写,一次写的话MySQL无法识别
		when 70 <= s.s_score and s.s_score < 85 then 'B'
		when 60 <= s.s_score and s.s_score < 70 then 'C'
		when 0 <= s.s_score and s.s_score < 60 then 'D'
		else '其他' end as 'category'
from Score s
join Course c 
on s.c_id = c.c_id;

3、完整代码

select
	s.c_id  编号
	,c.c_name  科目
	,sum(case when s.s_score >= 85 and  s.s_score<= 100 then 1 else 0 end) "[85,100]人数"
	,round(100 * (sum(case when s.s_score >= 85 and  s.s_score<= 100 then 1 else 0 end) / sum(case when s.s_score then 1 else 0 end)), 2) as '[85,100]百分比'
	,sum(case when s.s_score >= 70 and  s.s_score<= 85 then 1 else 0 end) "[70,85]人数"
	,round(100 * (sum(case when s.s_score >= 70 and  s.s_score<= 85 then 1 else 0 end) / sum(case when s.s_score then 1 else 0 end)), 2) as '[70,85]百分比'
	,sum(case when s.s_score >= 60 and  s.s_score<= 70 then 1 else 0 end) "[60,70]人数"
	,round(100 * (sum(case when s.s_score >= 60 and  s.s_score<= 70 then 1 else 0 end) / sum(case when s.s_score then 1 else 0 end)), 2) as '[60,70]百分比'
	,sum(case when s.s_score >= 0 and  s.s_score<= 60 then 1 else 0 end) "[0,60]人数"
	,round(100 * (sum(case when s.s_score >= 0 and  s.s_score<= 60 then 1 else 0 end) / sum(case when s.s_score then 1 else 0 end)), 2) as '[0,60]百分比'
from Score s
left join Course c
on s.c_id = c.c_id
group by s.c_id, c.c_name

参考方法

1、先统计每个阶段的人数和占比

select 
	c_id
	,sum(case when s_score > 85 and s_score <=100 then 1 else 0 end) as '85-100'
	,round(100 * (sum(case when s_score > 85 and s_score <= 100 then 1 else 0 end) / count(*)), 2) '占比'
from Score 
group by c_id;  -- 分课程统计总数和占比


-- 方式2
select 
	c_id
	,sum(case when s_score > 85 and s_score <=100 then 1 else 0 end) as '85-100'
	,round(100 * (sum(case when s_score > 85 and s_score <= 100 then 1 else 0 end) / count(case when s_score then 1 else 0 end)), 2) '占比'   -- 不同count(*)
from Score 
group by c_id;  

注意对比:

2、我们将4种情况同时查出来

select 
	c_id
	,sum(case when s_score > 85 and s_score <=100 then 1 else 0 end) as '85-100'
	,round(100 * (sum(case when s_score > 85 and s_score <= 100 then 1 else 0 end) / count(*)), 2) '[85,100]占比'
	,sum(case when s_score > 70 and s_score <=85 then 1 else 0 end) as '70-85'
	,round(100 * (sum(case when s_score > 70 and s_score <= 85 then 1 else 0 end) / count(*)), 2) '[70,85]占比'
	,sum(case when s_score > 60 and s_score <=70 then 1 else 0 end) as '60-70'
	,round(100 * (sum(case when s_score > 60 and s_score <= 70 then 1 else 0 end) / count(*)), 2) '[60,70]占比'
	,sum(case when s_score >=0 and s_score <=60 then 1 else 0 end) as '0-60'
	,round(100 * (sum(case when s_score > 0 and s_score <= 60 then 1 else 0 end) / count(*)), 2) '[0,60]占比'
from Score 
group by c_id;  -- 分课程统计总数和占比

3、将科目名称连接起来

-- 整体和自己的方法是类似的
select 
	s.c_id
	,c.c_name
	,sum(case when s_score > 85 and s_score <=100 then 1 else 0 end) as '85-100'
	,round(100 * (sum(case when s_score > 85 and s_score <= 100 then 1 else 0 end) / count(*)), 2) '[85,100]占比'
	,sum(case when s_score > 70 and s_score <=85 then 1 else 0 end) as '70-85'
	,round(100 * (sum(case when s_score > 70 and s_score <= 85 then 1 else 0 end) / count(*)), 2) '[70,85]占比'
	,sum(case when s_score > 60 and s_score <=70 then 1 else 0 end) as '60-70'
	,round(100 * (sum(case when s_score > 60 and s_score <= 70 then 1 else 0 end) / count(*)), 2) '[60,70]占比'
	,sum(case when s_score >=0 and s_score <=60 then 1 else 0 end) as '0-60'
	,round(100 * (sum(case when s_score > 0 and s_score <= 60 then 1 else 0 end) / count(*)), 2) '[0,60]占比'
from Score s
left join Course c
on s.c_id = c.c_id
group by s.c_id, c.c_name;    -- 分课程统计总数和占比

题目24

题目需求

查询学生的平均成绩及名次

分析过程

学生:Student

成绩:Score

平均:avg函数

名次:通过排序来解决

SQL实现
自己的方法

1、先求出每个人的平均分

-- 自己的方法

select 
	sc.s_id
	,s.s_name
	,round(avg(sc.s_score),2)  avg_score
from Score sc
join Student s
on sc.s_id=s.s_id
group by sc.s_id,s.s_name

2、我们对上面的结果进行排序

!!!MySQL5中是没有rank函数的,需要自己实现排序功能

-- MYSQL5.7中没有rank函数,所以通过自连接实现

select
	t1.s_id
	,t1.s_name
	,t1.avg_score
	,(select count(distinct t2.avg_score) 
		from (select 
            sc.s_id
            ,s.s_name
            ,round(avg(sc.s_score),2)  avg_score
          from Score sc
          join Student s
          on sc.s_id=s.s_id
          group by sc.s_id,s.s_name)t2    -- 临时表t2也是上面的结果
		where t2.avg_score >= t1.avg_score
		) rank

from (select 
        sc.s_id
        ,s.s_name
        ,round(avg(sc.s_score),2)  avg_score
      from Score sc
      join Student s
      on sc.s_id=s.s_id
      group by sc.s_id,s.s_name)t1   -- 临时表t1就是上面的结果
order by t1.avg_score desc;

参考方法
select
	a.s_id  -- 学号
	,@i:=@i+1 as '不保留空缺排名'   -- 直接i的自加
	,@k:=(case when @avg_score=a.avg_s then @k else @i end) as '保留空缺排名'
	,@avg_score:=avg_s as '平均分'  -- 表a中的值

from (select 
      	s_id
      	,round(avg(s_score), 2) as avg_s
      from Score 
      group by s_id
      order by 2 desc)a    -- 表a:平均成绩的排序和学号
      ,(select @avg_score:=0, @i:=0, @k:=0)b   -- 表b:通过变量设置初始值

实现rank函数

select 
	s.s_name  -- 姓名
	,s.s_score  -- 成绩
	,(select count(distinct t2.s_score)
    from Score t2
    where t2.s_score >= t1.s_score) rank   -- 在t2分数大的情况下,统计t2的去重个数
from Score t1
order by t1.s_score desc;   -- 分数降序排列

举例子来说明这个脚本:

姓名成绩
张三89
李四90
王五78
小明98
小红60
  1. 当t1.s_score=89,满足t2.s_score > = t1.s_score的有98,90和89,此时count(distinct t2.s_score) 的个数就是3
  2. 当t1.s_score=90,满足t2.s_score > = t1.s_score的有98和90,此时count(distinct t2.s_score) 的个数就是2
  3. 当t1.s_score=78,满足t2.s_score > = t1.s_score的有98、90、89和78,此时count(distinct t2.s_score) 的个数就是4
  4. 当t1.s_score=98,满足t2.s_score > = t1.s_score的只有98,此时count(distinct t2.s_score) 的个数就是1
  5. 当t1.s_score=60,满足t2.s_score > = t1.s_score的有89、90、78、98、60,此时count(distinct t2.s_score) 的个数就是5

通过上面的步骤,我们发现:t1中每个分数对应的个数就是它的排名

题目25

题目需求

查询各科成绩前三名的记录

分析过程

这题和第22题是属于一个类型的:找到每个科目的指定名次的成绩,使用的表是:Score

SQL实现
自己的方法

1、首先我们找出语文的前3名

select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '语文'
order by s.s_score desc   -- 降序之后取出前3条记录
limit 3;

2、通过同样的方法我们可以求出数学和英语的前3条记录,然后通过union进行联结,有待优化😭

-- 自己的脚本

(select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '语文'
order by s.s_score desc   -- 降序之后取出前3条记录
limit 3)

union

(select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '数学'
order by s.s_score desc   
limit 3)

union

(select s.s_id, s.s_score, c.c_name
from Score s
join Course c on s.c_id = c.c_id
where c.c_name = '英语'
order by s.s_score desc   
limit 3)

参考方法

通过Score表的自连接,表a中的值小于表b中的值,排序之后我们取前3

select
	a.s_id
	,a.c_id
	,a.s_score   -- 取出a中的成绩
from Score a
join Score b
on a.c_id = b.c_id
and a.s_score <= b.s_score   -- 表b中的成绩大
group by 1,2,3
having count(b.s_id) = 3
order by 2, 3 desc;

我们通过语文这个科目来理解上面的代码:前3名是80,80,76

-- 语文
select
	a.s_id
	,a.c_id
	,a.s_score   -- 3、此时a表的成绩就是我们找的  
from Score a
join Score b
on a.c_id = b.c_id
and a.s_score <= b.s_score  -- 1、判断a的分数小于等于b的分数,要带上等号
and a.c_id="01"
group by 1,2
having count(b.s_id) <= 3  -- 2、b中的个数至少有3个,应对分数相同的情形
order by 3 desc;   

-- 语文

select
	a.s_id
	,a.c_id
	,a.s_score   -- a表的成绩
from Score a
join Score b
on a.c_id = b.c_id
and a.s_score <= b.s_score   -- 1、判断a的分数小于等于b的分数,要带上等号
group by 1,2,3
having count(b.s_id) <= 3   -- 2、b中的个数至少有3个,应对分数相同的情形
order by 2, 3 desc;   -- 课程(2)的升序,成绩()3的降序

当然,以下是一些面向高级 Java 工程师的 MySQL 填空: 1. 在 MySQL 中,__数据库__ 是用于存储和管理数据的容器。 2. 在 MySQL 中,__表__ 是由一组具有相同结构的记录组成的数据集合。 3. 在 MySQL 中,__字段__ 是表中的一个列,用于存储特定类型的数据。 4. 在 MySQL 中,__主键__ 是用于唯一标识表中每个记录的字段或字段组合。 5. 在 MySQL 中,__外键__ 是用于建立表与表之间关系的字段,引用了其他表的主键。 6. 在 MySQL 中,__索引__ 是一种数据结构,用于加快数据检索操作的速度。 7. 在 MySQL 中,__事务__ 是由一个或多个操作组成的逻辑工作单元,要么全部执行成功,要么全部回滚。 8. 在 MySQL 中,__ACID__ 是指原子性、一致性、隔离性和持久性,用于描述事务的特性。 9. 在 MySQL 中,__存储过程__ 是一种预定义在数据库中的可重复使用的代码块。 10. 在 MySQL 中,__触发器__ 是一种特殊类型的存储过程,可以在表上的插入、更新或删除操作发生时自动执行。 11. 在 MySQL 中,__视图__ 是由一个或多个表的行和列组成的虚拟表,可以简化复杂的查询操作。 12. 在 MySQL 中,__游标__ 是用于按照一定顺序遍历结果集的数据库对象。 13. 在 MySQL 中,__连接__ 是通过某些条件将多个表中的数据关联起来的操作。 14. 在 MySQL 中,__子查询__ 是一个嵌套在其他查询语句中的查询语句。 15. 在 MySQL 中,__范式__ 是一种用于设计关系型数据库的规范化方法,包括第一范式、第二范式等。 16. 在 MySQL 中,__反范式__ 是一种通过冗余数据来提高查询性能的方法。 17. 在 MySQL 中,__存储引擎__ 是用于存储和检索数据的底层软件组件。 18. 在 MySQL 中,__InnoDB__ 是一个常用的支持事务和行级锁定的存储引擎。 19. 在 MySQL 中,__MyISAM__ 是一个常用的不支持事务但具有较高性能的存储引擎。 20. 在 MySQL 中,__备份与恢复__ 是一种用于保护数据库数据的重要手段,可以防止数据丢失。 21. 在 MySQL 中,__慢查询日志__ 是一种记录执行时间超过阈值的查询语句的日志。 22. 在 MySQL 中,__锁__ 是一种用于控制并发访问数据库的机制。 23. 在 MySQL 中,__主从复制__ 是一种将主数据库的更改复制到一个或多个从数据库的机制。 24. 在 MySQL 中,__分区__ 是一种将大表拆分为多个小表的技术,可以提高查询性能。 25. 在 MySQL 中,__分布式数据库__ 是一种将数据分布在多个物理节点上的数据库系统。 26. 在 MySQL 中,__批量插入__ 是一种将多条记录同时插入数据库的方法,可以提高插入性能。 27. 在 MySQL 中,__字符集__ 是一种用于存储和处理字符串数据的编码方式。 28. 在 MySQL 中,__连接池__ 是一种用于管理数据库连接的技术,可以提高性能和资源利用率。 29. 在 MySQL 中,__数据库优化器__ 是一种用于选择最优执行计划的组件。 30. 在 MySQL 中,__查询优化__ 是一种通过调整数据库结构、索引设计、查询重写等方式来提高查询性能的方法。 31. 在 MySQL 中,__复制__ 是一种将数据从一个数据库实例复制到另一个数据库实例的机制。 32. 在 MySQL 中,__分布式事务__ 是一种在多个数据库实例上保持一致性的事务处理方式。 33. 在 MySQL 中,__数据备份__ 是一种用于保护数据免受意外删除或损坏的手段。 34. 在 MySQL 中,__数据恢复__ 是一种通过备份或日志来还原数据库到某个时间点的操作。 35. 在 MySQL 中,__索引优化__ 是一种通过评估和优化索引来提高查询性能的方法。 36. 在 MySQL 中,__查询缓存__ 是一种缓存查询结果的机制,可以提高查询性能。 37. 在 MySQL 中,__并发控制__ 是一种用于处理多个并发事务的机制,保证数据一致性。 38. 在 MySQL 中,__存储过程调优__ 是一种通过优化存储过程代码来提高性能的方法。 39. 在 MySQL 中,__数据库分片__ 是一种将数据分散存储在多个物理节点上的技术,可以提高可扩展性。 40. 在 MySQL 中,__连接优化__ 是一种通过合理设计和使用连接来提高查询性能的方法。 41. 在 MySQL 中,__数据库安全__ 是一种保护数据库免受未经授权访问、数据泄露等威胁的措施。 42. 在 MySQL 中,__数据库监控__ 是一种实时监视数据库性能和活动的技术。 43. 在 MySQL 中,__查询分析器__ 是一种用于分析查询执行计划和性能瓶颈的工具。 44. 在 MySQL 中,__数据库版本控制__ 是一种用于管理数据库结构和数据变更的技术。 45. 在 MySQL 中,__外部键约束__ 是一种用于维护表之间关系完整性的机制。 46. 在 MySQL 中,__数据库压测__ 是一种通过模拟大量用户并发访问来评估数据库性能的方法。 47. 在 MySQL 中,__数据库分析__ 是一种通过分析数据来获得有关业务和性能的洞察的技术。 48. 在 MySQL 中,__数据库迁移__ 是一种将数据从一个数据库平台迁移到另一个数据库平台的过程。 49. 在 MySQL 中,__数据库优化__ 是一种通过调整数据库配置和参数来提高性能的方法。 50. 在 MySQL 中,__数据库设计__ 是一种通过合理设计表结构和关系来满足业务需求的方法。 这些目较为复杂,需要对 MySQL 的各个方面有一定的了解,并且对高级概念有所了解。希望能帮到你!如果你还有其他问,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值