• MySQL面试50题


    1 1到5

    -- 1 查询课程编号为‘01’的课程比‘02’的课程成绩高的所有学生的学号(重点)
    
    -- 整体的机构是先把三个表合并起来,再用where语句进行筛选,这里的as都可以省略,
    -- select 
    -- a.s_id as "sno", 
    -- a.s_score as "01", 
    -- b.s_score as "02",
    -- c.s_name 
    -- from 
    -- (select s_id,c_id,s_score from score where c_id = '01') as a
    -- inner join 
    -- (select s_id,c_id,s_score from score where c_id = '02')as b 
    -- on a.s_id = b.s_id 
    -- inner join 
    -- student as c on c.s_id = a.s_id 
    -- where a.s_score > b.s_score
    
    
    -- 2 查询平均成绩大于60分的学生学号和平均成绩
    
    -- -- 注意select后面的列尽量只选在group by后面出现的字段或使用统计函数统计过的字段,不要添加其它的列,因为没有意义
    -- select s_id, avg(s_score), c_id
    -- from score 
    -- group by s_id having avg(s_score)>60
    
    
    -- 3 查询所有同学的学号、姓名、选课总数、总成绩
    -- 使用的表:student,score
    
    -- 由于有的学生可能没有成绩,所以这里用左连接,
    -- select后面尽量只出现groupby后面的字段和统计字段,所以把名字列也加到groupby后面
    -- 为了避免求和列出现null值,所以判断为空值时赋值为0
    -- select a.s_id,a.s_name, count(b.s_id),
    -- sum(case when b.s_score is null then 0 else b.s_score end)
    -- from student as a left join score as b on a.s_id = b.s_id
    -- group by s_id,a.s_name
    
    
    -- 4 查询姓猴老师的个数
    -- 使用的表:teacher
    
    -- %代表任意字符,如果姓氏有重复可以用count(distinct t_name)来去重后再统计
    -- select count(t_name)
    -- from teacher 
    -- where t_name like '猴%'
    
    
    -- 5 查询没学过张三老师课的学生的学号,姓名(重点)
    
    -- 注意这里必须是用not in方法来解决,否则是错误的,即先把选过张三老师课程的学号找到,再取反
    -- select s_id, s_name from student
    -- where s_id not in (
    -- select s_id from score 
    -- where c_id = (
    -- select c_id from course 
    -- where t_id = 
    -- (select t_id from teacher where t_name = '张三')
    -- )
    -- )
    
    -- 错误写法,这样选出的是其它老师上的课
    -- select * from score where c_id != '02'
    
    -- 先把三个表合并,再进行选择
    -- select s_id, s_name from student
    -- where s_id not in 
    -- (
    -- select s.s_id from score as s
    -- inner join course as c on s.c_id = c.c_id
    -- inner join teacher as t on c.t_id = t.t_id
    -- where t.t_name = '张三'
    -- )
    View Code

    2 6到10

    -- 6 查询学过’张三‘老师所教的所有课的同学的学号,姓名(重点)
    
    -- 自己的代码,可能有问题,先把选张三老师的课的学号选出来,再从student表中选对应的学号
    -- select s_id,s_name from student as st
    -- where st.s_id in 
    -- (
    -- select s.s_id from score as s 
    -- inner join course as c on s.c_id = c.c_id 
    -- inner join teacher as t on t.t_id = c.t_id 
    -- where t.t_name = '张三'
    -- )
    
    -- 把四个表直接合并,再选择
    -- select st.s_id, st.s_name
    -- from student as st
    -- inner join score as s on st.s_id = s.s_id 
    -- inner join course as c on c.c_id = s.c_id 
    -- inner join teacher as t on t.t_id = c.t_id 
    -- where t.t_name = '张三'
    -- order by st.s_id
    -- 
    
    
    -- 7 查询学过编号为‘01’的课程且学过编号为‘02’的课程的学生的学号,姓名(重点) 
    
    -- 先利用子查询建立两个表,再用inner join表连接来筛选出都学过的学号,再对student表进行筛选
    -- select s_id, s_name from student
    -- where s_id in
    -- (
    -- select a.s_id from
    -- (select s_id from score where c_id = '01') as a
    -- inner join 
    -- (select s_id from score where c_id = '02') as b
    -- on a.s_id = b.s_id 
    -- )
    -- NULL求长度后结果是null  select LENGTH(null)
    
    
    -- 8 查询课程编号为‘02’的总成绩(不重点)
    
    -- select sum(s_score),avg(s_score),count(distinct s_id) from score 
    -- where c_id = '02'
    -- -- 利用groupby可以对不同课程做统计
    -- select c_id,sum(s_score),avg(s_score),count(distinct s_id) from score 
    -- group by c_id
    -- -- 或者利用having
    -- select c_id,sum(s_score),avg(s_score),count(distinct s_id) from score 
    -- group by c_id having c_id = '02'
    
    
    -- 9 查询所有课程成绩小于60分的学生的学号,姓名
    
    -- 先计算每个同学小于60分的课程的个数,再计算每个同学所学的课程数,然后利用子查询把两个表按学号连接起来
    -- 再对表进行筛选,最后和student表进行联结
    -- 注意1>select后面是最后要展示的列  2>where要再join的后面不能先筛选了再进行join
    -- select a.s_id, st.s_name
    -- from 
    -- (
    -- select s_id, count(c_id) as cnt from score 
    -- where s_score < 60
    -- group by s_id
    -- ) as a
    -- inner join 
    -- (
    -- select s_id, count(c_id) as cnt from score 
    -- group by s_id
    -- ) as b 
    -- on a.s_id = b.s_id 
    -- inner join student as st 
    -- on a.s_id = st.s_id
    -- where a.cnt = b.cnt
    
    
    -- 10 查询没有学全所有课的学生的学号、姓名(重点)
    
    -- 利用group by进行聚合筛选
    -- select只能跟列名或者*,不能直接选择表名,选表名会报错 
    -- 利用in方法的时候后面只能选一个列,选多个列的时候无法筛选,会报错
    -- select s_id, s_name from student 
    -- where s_id in 
    -- (
    -- select s_id from score
    -- group by s_id having count(c_id) < (select count(distinct c_id) from course)
    -- )
    
    -- 上面方法有缺陷,因为可能有的学生没有成绩,所以在score表中不会出现,改进后的方法
    -- 把student表和score表合并后再筛选
    -- 注意这里之所以要用left join是因为student中的学生多,是一对多,
    -- select st.s_id, st.s_name from student as st 
    -- left join score as sc 
    -- on st.s_id = sc.s_id 
    -- group by st.s_id having count(distinct sc.c_id) < (select count(distinct c_id) from course)
    View Code

    3 11到15

    -- 11 查询至少有一门课与学号为“01”的学生所学课程相同的学生的学号和姓名(重点)
    
    -- 用in效率较低,适合小数据 注意and在括号外用
    -- select * from student 
    -- where s_id in 
    -- (select distinct s_id from score
    -- where c_id in  
    -- (select c_id from score 
    -- where s_id = '01') 
    -- and s_id != '01')
    -- 当表较大的时候,用inner join ... on 比用in效率高
    -- select a.s_id,a.s_name from student as a
    -- inner join 
    -- (
    -- (select distinct s_id from score
    -- where c_id in  
    -- (select c_id from score 
    -- where s_id = '01') 
    -- and s_id != '01')
    -- ) as b on a.s_id = b.s_id
    
    
    -- 12 查询和“01”号同学所学课程完全相同的其他同学的学号(重点)
    
    -- 思路:01号同学选了(01 02 03)三门课程,先选出所有和01号同学学习课程数目相同的学生,
    --       再把其中选了其它课程的同学删除,或者反过来理解也行,
    -- select * from student 
    -- where s_id in 
    -- (
    -- select s_id from score 
    -- where s_id != '01'
    -- group by s_id having count(distinct c_id) = (select count(distinct c_id) from score where s_id = '01')
    -- )
    -- and s_id not in
    -- (
    -- select distinct s_id from score 
    -- where c_id not in 
    -- (select c_id from score where s_id = '01')
    -- )
    
    -- 15 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩(重点)
    
    -- 先把满足条件的学号筛选处来,再对合并后的表格进行筛选和groupby
    -- select st.s_id, st.s_name, avg(s_score) from student as st 
    -- inner join score as sc on st.s_id = sc.s_id
    -- where st.s_id in 
    -- (
    -- select s_id from score 
    -- where s_score < 60
    -- group by s_id having count(distinct c_id) >= 2
    -- )
    -- group by s_id, s_name
    View Code

    4 16到20

    -- 16 检索"01"课程分数小于60,按分数降序排列的学生信息(和34题重复,不重点)
    
    -- 考察了order by ,where实际上是用于筛选条件的
    -- select st.*,sc.c_id,sc.s_score from student as st 
    -- inner join score as sc on st.s_id = sc.s_id
    -- where sc.c_id = '01' and sc.s_score < 60
    -- order by sc.s_score desc
    
    
    -- 17 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩(重重点与35一样)
    
    -- 自己的代码,注意inner join后面必须要有on,否则会出错,代码有问题,没有课程列
    -- select k.s_id, k.s_name, avg(s_score) from 
    -- (
    -- select st.*, sc.s_score from student as st
    -- inner join score as sc on st.s_id = sc.s_id
    -- ) as k
    -- group by s_id  
    -- order by avg(s_score) desc
    
    -- 这个代码有问题,因为s_score列并没有意义,也不满足题目要求
    -- select sc1.s_id, sc1.s_score, avg_s_score  from score as sc1 
    -- inner join 
    -- (
    -- select s_id, avg(s_score) as avg_s_score from score 
    -- group by s_id
    -- ) as sc2 on sc1.s_id = sc2.s_id 
    -- order by avg_s_score desc
    
    -- 这个写法非常巧妙,这里之所以要用统计函数max是因为group by前最好只出现group by使用过的列或统计函数
    -- 这里的目的并不是为了求max,而是因为group by用法的原因,
    -- select s_id '学号',
    -- max(case when c_id = '01' then s_score else null end) '语文',
    -- max(case when c_id = '02' then s_score else null end) '数学',
    -- max(case when c_id = '03' then s_score else null end) '英语',
    -- avg(s_score) '平均成绩'
    -- from score 
    -- group by s_id
    -- order by avg(s_score) desc
    
    
    -- 18 查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,
    -- 最高分,最低分,平均分,及格率,中等率,优良率,优秀率
    
    -- 这个题主要考察了group by后聚合函数case when的用法
    -- select 
    -- sc.c_id
    -- ,c.c_name
    -- ,max(s_score)
    -- ,min(s_score)
    -- ,avg(s_score)
    -- ,sum(case when sc.s_score>=60 then 1 else 0 end)/count(s_id) '及格率'
    -- ,sum(case when sc.s_score>=70 and sc.s_score<=80 then 1 else 0 end)/count(s_id) '中等率'
    -- ,sum(case when sc.s_score>=80 and sc.s_score<=90 then 1 else 0 end)/count(s_id) '优良率'
    -- ,sum(case when sc.s_score>=90 and sc.s_score<=100 then 1 else 0 end)/count(s_id) '优秀率'
    -- from score as sc 
    -- inner join course as c on sc.c_id = c.c_id 
    -- group by c_id 
    
    
    -- 19 按各科成绩进行排序,并显示排名(重点row_number) row_number()over (order by 列)
    
    -- rank()       跳跃排序,即如果第二名和第三名分数一样,则二三都是2,第四名为4
    -- dense_rank() 连续排序,二三同上,第四名为3,即名次连续
    -- row_number() 无重复值排序,直接为1 2 3 4,不分是否分数相等
    -- select s_id, c_id, s_score, row_number()
    -- over(order by s_score desc) from score
    
    
    -- 20 查询学生的总成绩并进行排名(不重点)
    
    -- 有问题,为什么列名sum(s_score)在外面无法选择
    select * 
    from student as st 
    inner join 
    (
    select s_id, sum(s_score) from score
    group by s_id
    order by sum(s_score) desc
    ) as sc on st.s_id = sc.s_id
    View Code

    5 21到30

    -- 21 查询不同老师所教不同课程平均分从高到低显示(不重点)
    
    -- 自己的代码,和视频里不一样,把表合并为一个大表后,前面可以自由的选择列
    -- select t.t_name, c.c_name, avg(s_score) from teacher as t
    -- left join course as c on c.t_id = t.t_id
    -- left join score as sc on sc.c_id = c.c_id 
    -- group by t.t_name, c.c_name
    -- order by avg(s_score) desc
    
    
    -- 22 查询所有课程的成绩第2名到第3名的学生信息及该课程成绩(重要 25类似)
    
    -- 考察了窗口函数,先做一个子查询,再用where对m列进行筛选,这里的窗口函数其实可以用rank,因为有相同分数的情况
    -- select * 
    -- from 
    -- (select st.s_id, st.s_name, c_id, s_score, 
    -- row_number() over (partition by c_id order by s_score desc) m
    -- from score as sc 
    -- inner join student as st 
    -- on sc.s_id = st.s_id) as tab 
    -- where m in (2,3)
    
    
    -- 23 使用分段[100-85],[85-70],[70-60],[<60]来统计各科成绩,分别统计各分数段人数:课程ID和课程名称(重点和18题类似)
    
    -- 这个题主要考察了统计函数sum 和 count的不同用法,注意count是对非空值进行统计
    -- 这里的内连接和视频不同,导致结果不同
    -- select c.c_id
    -- , c.c_name
    -- , sum(case when sc.s_score<=100 and sc.s_score>=85 then 1 else 0 end) '[100-85]'
    -- , count(case when sc.s_score<=85 and sc.s_score>=70 then 3 else null end) '[85-70]'
    -- , count(case when sc.s_score<=70 and sc.s_score>=60 then 3 else null end) '[70-60]'
    -- , count(case when sc.s_score<60 then 3 else null end) '[<60]'
    -- from course as c 
    -- inner join score as sc 
    -- on c.c_id = sc.c_id 
    -- group by c.c_id, c.c_name
    
    
    -- 24 查询学生平均成绩及其名次(同19题,重点)
    
    -- 注意窗口函数不用partition by时,就是对整体的数据进行排序
    -- select s_id
    -- , avg(s_score)
    -- , row_number() over (order by avg(s_score) desc)
    -- from score 
    -- group by s_id
    
    
    -- 26 查询每门课程被选修的学生数(不重点)
    
    -- group by后面的列尽量都在select中
    -- select c.c_id, c.c_name, count(distinct sc.s_id) '学生数' from score as sc
    -- inner join course as c 
    -- on sc.c_id = c.c_id
    -- group by c.c_id, c.c_name 
    
    
    -- 27 查询出只有两门课程的全部学生的学号和姓名(不重点)
    
    -- 主要考察如何作筛选
    -- 利用子查询,先把s_id找出来,再筛选
    -- select st.s_id, st.s_name from student as st
    -- where s_id in 
    -- (
    -- select s_id from score 
    -- group by s_id having count(distinct c_id)=2
    -- )
    
    -- 先把两个表联结后再group by利用having进行筛选
    -- select st.s_id, st.s_name from score as sc 
    -- inner join student as st 
    -- on sc.s_id = st.s_id 
    -- group by s_id having count(distinct c_id)=2
    
    
    -- 28 查询男生、女生人数(不重点)
    
    -- 这道题把group by去掉也行
    -- 利用count实现
    -- select s_sex
    -- , count(s_sex) '人数'
    -- from student
    -- group by s_sex 
    -- 利用sum实现
    -- select 
    -- sum(case when s_sex='男' then 1 else 0 end) '男',
    -- sum(case when s_sex='女' then 1 else 0 end) '女'
    -- from student
    
    -- 29 查询名字中含有"风"字的学生信息(不重点)
    
    -- 考察like的用法,%风是以风开头,风%是以风结尾
    -- select * from student where s_name like '%风%'
    View Code

    6 31到40

    -- 31 查询1990年出生的学生名单(重点year)
    
    -- 考察时间函数的用法
    -- select * from student where year(s_birth) = 1990
    -- select month('190101')
    -- 时间格式如下的可以直接转换
    -- YYYYMM-DD   YYYYMMDD   YYYY/MM//DD  YYMMDD
    
    
    -- 32 查询平均成绩大于等于85的所有学生的学号、姓名和平均成绩(不重要)
    
    -- 注意group by后面用having可以起筛选作用,这道题也可以先对score表求平均后,再用子查询和表student做联结
    -- select st.s_id, st.s_name, avg(s_score) as '平均成绩' from student as st 
    -- inner join score as sc 
    -- on st.s_id = sc.s_id 
    -- group by st.s_id, st.s_name having avg(s_score)>85
    
    
    -- 33 查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列(不重要)
    
    -- 考察order by同时排序两列的用法
    -- select sc.c_id, c.c_name, avg(s_score) from score as sc 
    -- inner join course as c on sc.c_id = c.c_id 
    -- group by c_id 
    -- order by avg(s_score) asc, c_id desc 
    
    
    -- 34 查询课程名称为"数学",且分数低于60的学生姓名和分数(不重点)
    
    -- 考察了利用where进行条件筛选,写程序时先筛选完再inner join联结student表来添加名字列
    -- select st.s_id, st.s_name, sc.s_score from score as sc 
    -- inner join course as c on sc.c_id = c.c_id
    -- inner join student as st on sc.s_id = st.s_id
    -- where c.c_name = '数学' and sc.s_score<60
    
    
    -- 35 查询所有学生的课程及分数情况(重点)
    
    -- 这个题主要考察了利用group by把一列按条件拆成多列的写法,这里case when的用法是groupby后的每个c.c_name
    -- 都会与语文进行比较,所以除了语文,其余都是空值,在空值和语文分数中取最大值,结果就是语文分数,
    -- select st.s_id, st.s_name,
    -- max( case when c.c_name='语文' then sc.s_score else null end) '语文',
    -- max( case when c.c_name='数学' then sc.s_score else null end) '数学',
    -- max( case when c.c_name='英语' then sc.s_score else null end) '英语'
    -- from score as sc 
    -- inner join student as st on sc.s_id = st.s_id
    -- inner join course as c on sc.c_id = c.c_id 
    -- group by st.s_id, st.s_name
    
    
    -- 36 查询课程成绩在70分以上的姓名、课程名称和分数(重点)
    
    -- 由于是score对student course表都是多对一,所以可以用inner join
    -- select st.s_name, c.c_name, sc.s_score  from score as sc 
    -- inner join student as st on sc.s_id = st.s_id 
    -- inner join course as c on c.c_id = sc.c_id 
    -- where sc.s_score > 70
    
    -- 37查询不及格的课程并按课程号从大到小排列(不重点)
    
    -- select st.s_id, st.s_name, c.c_name, c.c_id, sc.s_score
    -- from score as sc 
    -- inner join course as c on sc.c_id = c.c_id
    -- inner join student as st on sc.s_id = st.s_id
    -- where sc.s_score < 60
    -- order by c.c_id desc
    
    -- 38 查询课程编号为03且课程成绩在80分以上的学生的学号和姓名(不重要)
    
    -- select st.s_id, st.s_name, sc.s_score, c.c_name from score as sc 
    -- inner join student as st on st.s_id = sc.s_id 
    -- inner join course as c on c.c_id = sc.c_id
    -- where sc.c_id='03' and sc.s_score>80 
    
    -- 39 求每门课程的学生人数(不重要)
    
    -- select c.c_id, c.c_name, count(distinct c.c_id) as '人数' from score as sc 
    -- inner join course as c on sc.c_id = c.c_id 
    -- group by c.c_id, c.c_name
    
    -- 40查询选修“张三”老师所授课程的学生中成绩最高的学生姓名及其成绩(重要top)
    
    -- 考察了limit的用法,用于排序后取某些行,左闭右开,
    -- select st.s_id, st.s_name, sc.s_score from score as sc 
    -- inner join course as c on c.c_id=sc.c_id
    -- inner join teacher as t on t.t_id=c.t_id 
    -- inner join student as st on st.s_id=sc.s_id
    -- where t.t_name='张三' 
    -- order by sc.s_score desc limit 0,1
    View Code

    7 41到50

    -- 41 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩 (重点)
    
    -- 多个子查询嵌套,先把只选一个课程的去掉,再两次group by进行筛选
    -- select s_id from 
    -- (
    -- select b.s_id, b.s_score from score as b 
    -- inner join 
    -- (
    -- select s_id from score 
    -- group by s_id having count(distinct c_id)>1
    -- ) as c on b.s_id=c.s_id
    -- group by b.s_id, b.s_score
    -- ) as a 
    -- group by s_id having count(s_id)=1
    
    
    -- 43 统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,
    --    查询结果按人数降序排列,若人数相同,按课程号升序排列(不重要)
    
    -- where后面不能跟聚合函数
    -- select sc.c_id, count(distinct s_id) from score as sc 
    -- group by sc.c_id having count(s_id)>5
    -- order by count(s_id) desc, c_id asc
    
    -- 44、检索至少选修两门课程的学生学号(不重要)
    
    -- 使用count函数的时候要判断是否需要用distinct
    -- select s_id, count(distinct c_id) from score 
    -- group by s_id having count(distinct c_id)>=2
    
    -- 45 查询选修了全部课程的学生信息(重点划红线地方)
    
    -- 要学会这里计算course表时的子查询,直接用count(course.c_id)会报错,因为course表没有被选中
    -- select s_id from score as sc 
    -- group by s_id having count(distinct c_id)=
    -- (select count(distinct c_id) from course)
    
    
    -- 46 查询各学生的年龄(精确到月份)
    -- floor()函数用于向下取整, datediff(date1, data2) 第一个参数减第二个差值是天数,now()获取当前时间
    -- select s_id, s_birth, floor(datediff(now(), s_birth)/365) as '年龄' from student
    
    -- 47 查询没学过“张三”老师讲授的任一门课程的学生姓名
    
    -- 必须用取反的方法not in
    -- select * from student 
    -- where s_id not in 
    -- (
    -- select sc.s_id from score as sc 
    -- inner join course as c on sc.c_id=c.c_id
    -- inner join teacher as t on t.t_id=c.t_id 
    -- where t.t_name='张三'
    -- )
    
    -- 48 查询下周过生日的同学
    
    -- 先把年份做字符串替换,替换成今年的,再做判断,年末不够严谨
    -- select * from student
    -- where week(concat('2020-', substring(s_birth, 6, 5)), 1) = week('2019-05-15', 1)+1
    
    -- 49 查询本月过生日的人
    -- select * from student 
    -- where month(s_birth)=month(now())
    
    -- 50 查询下月过生日的人
    -- 为防止出现13直接对12取整
    -- select * from student 
    -- where month(s_birth)=mod(month(now())+1, 12)
    View Code
  • 相关阅读:
    简单排序
    vue router在history模式下 如何部署在tomcat上
    概率论复习纲要
    MyBatis学习笔记(持续更新 2021/01/06- 2021/01/10)
    JavaWeb学习笔记(持续编辑2021/1/5-)
    2021/01/10周学习总结
    将WiFi搞得可以认证石铁大校园网(小米3路由器)
    对老师的建议
    自我感觉加分项
    github、gitee冲突配置ssh key
  • 原文地址:https://www.cnblogs.com/xxswkl/p/12843681.html
Copyright © 2020-2023  润新知