网上很多这样的题目,好像一共50道,但是其中有的题目的解法是错误的。题目用了一题多解(多解思路必须要掌握)
bug:
score这张表当中没有成绩的同学不显示
mysql 高版本支持了
窗口函数
,并且对group by 等语法要求更加严格
# 查看mysql版本
select VERSION();
# 8.0.31
create database test1;
use test1;
create table student
(
s_id varchar(10),
s_name varchar(10),
s_birth datetime,
s_sex varchar(10)
);
insert into student (s_id, s_name, s_birth, s_sex) values ('01', '赵雷', '1990-01-01 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('02', '钱电', '1990-12-21 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('03', '孙风', '1990-05-20 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('04', '李云', '1990-08-06 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('05', '周梅', '1991-12-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('06', '吴兰', '1992-03-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('07', '郑竹', '1989-07-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('08', '王菊', '1990-01-20 00:00:00', '女');
create table score
(
s_id varchar(10),
c_id varchar(10),
s_score decimal(18, 1)
);
insert into score (s_id, c_id, s_score) values ('01', '01', 80.0);
insert into score (s_id, c_id, s_score) values ('01', '02', 90.0);
insert into score (s_id, c_id, s_score) values ('01', '03', 99.0);
insert into score (s_id, c_id, s_score) values ('02', '01', 70.0);
insert into score (s_id, c_id, s_score) values ('02', '02', 60.0);
insert into score (s_id, c_id, s_score) values ('02', '03', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '01', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '02', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '03', 80.0);
insert into score (s_id, c_id, s_score) values ('04', '01', 50.0);
insert into score (s_id, c_id, s_score) values ('04', '02', 30.0);
insert into score (s_id, c_id, s_score) values ('04', '03', 20.0);
insert into score (s_id, c_id, s_score) values ('05', '01', 76.0);
insert into score (s_id, c_id, s_score) values ('05', '02', 87.0);
insert into score (s_id, c_id, s_score) values ('06', '01', 31.0);
insert into score (s_id, c_id, s_score) values ('06', '03', 34.0);
insert into score (s_id, c_id, s_score) values ('07', '02', 89.0);
insert into score (s_id, c_id, s_score) values ('07', '03', 98.0);
create table course
(
c_id varchar(10),
c_name varchar(10),
t_id varchar(10)
);
insert into course (c_id, c_name, t_id) values ('01', '语文', '02');
insert into course (c_id, c_name, t_id) values ('02', '数学', '01');
insert into course (c_id, c_name, t_id) values ('03', '英语', '03');
create table teacher
(
t_id varchar(10),
t_name varchar(10)
);
insert into teacher (t_id, t_name) values ('01', '张三');
insert into teacher (t_id, t_name) values ('02', '李四');
insert into teacher (t_id, t_name) values ('03', '王五');
bug:
score这张表当中没有成绩的不显示
(正确的做法:没有参加考试的同学成绩直接显示为0,而不是不显示),这样会导致问题。后来我在发现问题后,也不想再去修改这张表的数据了,因为太懒
典型的分组TopN的弱化题目
select st.s_id,
st.s_name,
c.c_name,
sc.s_score,
row_number() over (partition by sc.c_id order by sc.s_score desc ) as ranking
from score sc
join student st on st.s_id = sc.s_id
join course c on sc.c_id = c.c_id;
s_id | s_name | c_name | s_score | ranking |
---|---|---|---|---|
01 | 赵雷 | 语文 | 80.0 | 1 |
03 | 孙风 | 语文 | 80.0 | 2 |
05 | 周梅 | 语文 | 76.0 | 3 |
02 | 钱电 | 语文 | 70.0 | 4 |
04 | 李云 | 语文 | 50.0 | 5 |
06 | 吴兰 | 语文 | 31.0 | 6 |
01 | 赵雷 | 数学 | 90.0 | 1 |
07 | 郑竹 | 数学 | 89.0 | 2 |
05 | 周梅 | 数学 | 87.0 | 3 |
03 | 孙风 | 数学 | 80.0 | 4 |
02 | 钱电 | 数学 | 60.0 | 5 |
04 | 李云 | 数学 | 30.0 | 6 |
01 | 赵雷 | 英语 | 99.0 | 1 |
07 | 郑竹 | 英语 | 98.0 | 2 |
03 | 孙风 | 英语 | 80.0 | 3 |
02 | 钱电 | 英语 | 80.0 | 4 |
06 | 吴兰 | 英语 | 34.0 | 5 |
04 | 李云 | 英语 | 20.0 | 6 |
bug:
无成绩的没有排名(因为score这张表没有成绩的都不显示)
select *
from (select st.s_id,
st.s_name,
c.c_name,
sc.s_score,
row_number() over (partition by sc.c_id order by sc.s_score desc ) as ranking
from score sc
join student st on st.s_id = sc.s_id
join course c on sc.c_id = c.c_id) t1
where t1.ranking >= 2
and ranking <= 3;
s_id | s_name | c_name | s_score | ranking |
---|---|---|---|---|
03 | 孙风 | 语文 | 80.0 | 2 |
05 | 周梅 | 语文 | 76.0 | 3 |
07 | 郑竹 | 数学 | 89.0 | 2 |
05 | 周梅 | 数学 | 87.0 | 3 |
07 | 郑竹 | 英语 | 98.0 | 2 |
02 | 钱电 | 英语 | 80.0 | 3 |
select st.s_id,
st.s_name,
sum(sc.s_score) as sumScore,
row_number() over (order by sum(sc.s_score) desc ) as ranking
from score sc
join student st on st.s_id = sc.s_id
join course c on sc.c_id = c.c_id
group by st.s_id, st.s_name;
s_id | s_name | sumscore | ranking |
---|---|---|---|
01 | 赵雷 | 269.0 | 1 |
03 | 孙风 | 240.0 | 2 |
02 | 钱电 | 210.0 | 3 |
07 | 郑竹 | 187.0 | 4 |
05 | 周梅 | 163.0 | 5 |
04 | 李云 | 100.0 | 6 |
06 | 吴兰 | 65.0 | 7 |
bug:
score这张表当中没有成绩的都不显示,导致王菊没有显示出来
会了下边的题目,求TopN就非常简单
这里的方法2有局限性
-- 方法1
select *
from (select st.s_id,
st.s_name,
sum(sc.s_score) as sumScore,
row_number() over (order by sum(sc.s_score) desc ) as ranking
from score sc
join student st on st.s_id = sc.s_id
join course c on sc.c_id = c.c_id
group by st.s_id, st.s_name) t1
where t1.ranking >= 2
and t1.ranking <= 3;
-- 方法2
select st.s_id,
st.s_name,
sum(sc.s_score) as sumScore,
row_number() over (order by sum(sc.s_score) desc ) as ranking
from score sc
join student st on st.s_id = sc.s_id
join course c on sc.c_id = c.c_id
group by st.s_id, st.s_name
limit 1,2;
s_id | s_name | sumscore | ranking |
---|---|---|---|
03 | 孙风 | 240.0 | 2 |
02 | 钱电 | 210.0 | 3 |
这里的2种解法都很重要
解法1
select st.s_id,
st.s_name,
sum(case when c.c_name = '语文' then sc.s_score else 0 end) as chinese,
sum(case when c.c_name = '数学' then sc.s_score else 0 end) as math,
sum(case when c.c_name = '英语' then sc.s_score else 0 end) as english,
sum(sc.s_score) as sumScore,
row_number() over (order by sum(sc.s_score) desc ) as ranking
from score sc
join course c on sc.c_id = c.c_id
join student st on st.s_id = sc.s_id
group by st.s_id, st.s_name;
# case when 可以用 if 来简化
sum(case when c.c_name = '语文' then sc.s_score else 0 end)<=>sum(if(c.c_name = '语文', sc.s_score, 0))
s_id | s_name | chinese | math | english | sumScore | ranking |
---|---|---|---|---|---|---|
01 | 赵雷 | 80.0 | 90.0 | 99.0 | 269.0 | 1 |
03 | 孙风 | 80.0 | 80.0 | 80.0 | 240.0 | 2 |
02 | 钱电 | 70.0 | 60.0 | 80.0 | 210.0 | 3 |
07 | 郑竹 | 0.0 | 89.0 | 98.0 | 187.0 | 4 |
05 | 周梅 | 76.0 | 87.0 | 0.0 | 163.0 | 5 |
04 | 李云 | 50.0 | 30.0 | 20.0 | 100.0 | 6 |
06 | 吴兰 | 31.0 | 0.0 | 34.0 | 65.0 | 7 |
解法2
select t0.s_id,
t0.s_name,
ifnull(t1.chinese, 0),
ifnull(t2.math, 0),
ifnull(t3.english, 0),
t0.sumScore,
t0.ranking
from (select st.s_id,
st.s_name,
sum(sc.s_score) as sumScore,
row_number() over (order by sum(sc.s_score) desc ) as ranking
from score sc
join student st on sc.s_id = st.s_id
group by st.s_id, st.s_name) t0
left join (select sc.s_id,
sc.s_score as chinese
from score sc
join course c on sc.c_id = c.c_id and c.c_name = '语文') t1 on t0.s_id = t1.s_id
left join (select sc.s_id,
sc.s_score as math
from score sc
join course c on sc.c_id = c.c_id and c.c_name = '数学') t2 on t0.s_id = t2.s_id
left join (select sc.s_id,
sc.s_score as english
from score sc
join course c on sc.c_id = c.c_id and c.c_name = '英语') t3
on t0.s_id = t3.s_id;
格式要求:
显示课程ID,课程name,最高分,最低分,平均分,及格率,良好率
评级标准:
及格为>=60,良好为:[60,80]
select c.c_id,
c.c_name,
max(sc.s_score) as maxScore,
min(sc.s_score) as minScore,
round(avg(sc.s_score), 2) as avgScore,
# count+if
# count时,必须用null,不能用0,因为0所在也被计数,null则不被计数
round(count(if(sc.s_score >= 60, 1, null)) / count(sc.s_id), 2) as passRate,
# sum+case when
round(sum(case when sc.s_score >= 60 and sc.s_score <= 80 then 1 else 0 end) / count(sc.s_id), 2) as goodRate
from score sc
join course c on sc.c_id = c.c_id
group by c.c_id, c.c_name;
c_id | c_name | maxScore | minScore | avgScore | passRate | goodRate |
---|---|---|---|---|---|---|
01 | 语文 | 80.0 | 31.0 | 64.50 | 0.67 | 0.67 |
02 | 数学 | 90.0 | 30.0 | 72.67 | 0.83 | 0.33 |
03 | 英语 | 99.0 | 20.0 | 68.50 | 0.67 | 0.33 |
select st.s_id,
st.s_name,
sum(case when c.c_name = '语文' then sc.s_score else 0 end) as chinese,
sum(case when c.c_name = '数学' then sc.s_score else 0 end) as math,
sum(case when c.c_name = '英语' then sc.s_score else 0 end) as english,
sum(sc.s_score) as sumScore,
row_number() over (order by sum(sc.s_score) desc ) as ranking
from score sc
join course c on sc.c_id = c.c_id
join student st on st.s_id = sc.s_id
group by st.s_id, st.s_name
union all
select '单科总成绩', # 将整个表看成一组
'',
sum(t1.chinese),
sum(t1.math),
sum(t1.english),
'',
''
from (select st.s_id,
st.s_name,
sum(case when c.c_name = '语文' then sc.s_score else 0 end) as chinese,
sum(case when c.c_name = '数学' then sc.s_score else 0 end) as math,
sum(case when c.c_name = '英语' then sc.s_score else 0 end) as english
from score sc
join course c on sc.c_id = c.c_id
join student st on st.s_id = sc.s_id
group by st.s_id, st.s_name) t1;
s_id | s_name | chinese | math | english | sumScore | ranking |
---|---|---|---|---|---|---|
01 | 赵雷 | 80.0 | 90.0 | 99.0 | 269.0 | 1 |
03 | 孙风 | 80.0 | 80.0 | 80.0 | 240.0 | 2 |
02 | 钱电 | 70.0 | 60.0 | 80.0 | 210.0 | 3 |
07 | 郑竹 | 0.0 | 89.0 | 98.0 | 187.0 | 4 |
05 | 周梅 | 76.0 | 87.0 | 0.0 | 163.0 | 5 |
04 | 李云 | 50.0 | 30.0 | 20.0 | 100.0 | 6 |
06 | 吴兰 | 31.0 | 0.0 | 34.0 | 65.0 | 7 |
单科总成绩 | 387.0 | 436.0 | 411.0 |
select *
from student
where s_id in (select s_id
from score
where s_id != '01'
group by s_id
having group_concat(distinct c_id order by c_id separator '|') =
(select group_concat(distinct c_id order by c_id separator '|')
from score
where s_id = '01'));
-- 方法2 join
select *
from student
where s_id in (select s_id
from (select s_id,
group_concat(distinct c_id order by c_id separator '|') as a
from score
where s_id != '01'
group by s_id) t1
join (select group_concat(distinct c_id order by c_id separator '|') as b
from score
where s_id = '01') t2
on t1.a = t2.b);
-- 方法3 join
select st.*
from (select s_id,
group_concat(distinct c_id order by c_id separator '|') as a
from score
where s_id != '01'
group by s_id) t1
join (select group_concat(distinct c_id order by c_id separator '|') as b
from score
where s_id = '01') t2
on t1.a = t2.b
join student st on st.s_id = t1.s_id;
s_id | s_name | s_birth | s_sex |
---|---|---|---|
02 | 钱电 | 1990-12-21 00:00:00 | 男 |
03 | 孙风 | 1990-05-20 00:00:00 | 男 |
04 | 李云 | 1990-08-06 00:00:00 | 男 |
以下必须是HQL语法规则
select *
from student
join (select s_id
from (select s_id,
concat_ws('|', collect_set(c_id)) as num1
from score
where s_id <> '01'
group by s_id) t1
join(select concat_ws('|', collect_set(c_id)) as num2
from score
where s_id = '01') t2
on t1.num1 = t2.num2) t3
on student.s_id = t3.s_id;
-- 方法1
select *
from student
where s_id in (select s_id
from (select s_id,
group_concat(distinct c_id order by c_id separator '|') as a
from score
where s_id != '01'
group by s_id) t1
left join (select group_concat(distinct c_id order by c_id separator '|') as b
from score
where s_id = '01') t2
on t1.a = t2.b
where t2.b is null);
-- 方法2(适用于hive)
select student.s_id, student.s_name
from student
join (select *
from (select s_id, concat_ws('|', collect_set(c_id)) as num1
from score
group by s_id
having s_id <> '01') t1 -- <>等价于!=
left join (select concat_ws('|', collect_set(c_id)) as num2
from score
where s_id = '01'
) t2 on t1.num1 = t2.num2
where t2.num2 is null) t3
on t3.s_id = student.s_id;
-- answer3
可以使用上面提到过的 group_concat
s_id | s_name | s_birth | s_sex |
---|---|---|---|
5 | 周梅 | 1991-12-01 00:00:00 | 女 |
6 | 吴兰 | 1992-03-01 00:00:00 | 女 |
7 | 郑竹 | 1989-07-01 00:00:00 | 女 |
8 | 王菊 | 1990-01-20 00:00:00 | 女 |
别处有引用,勿动!!!
-- answer 2
select *
from student
where s_id in (select s_id
from score
group by s_id
having count(distinct c_id) < (select count(distinct c_id) from course));
-- answer 3
select student.*
from student
where s_id in (select s_id
from (select s_id,
count(distinct c_id) as num1
from score
group by s_id) t1
left join(select count(distinct c_id) as num2
from course) t2
on t1.num1 = t2.num2
where t2.num2 is null);
s_id | s_name | s_birth | s_sex |
---|---|---|---|
05 | 周梅 | 1991-12-01 | 女 |
06 | 吴兰 | 1992-03-01 | 女 |
07 | 郑竹 | 1989-07-01 | 女 |
08 | 王菊 | 1990-01-20 | 女 |
hive中如果使用concat_ws(‘|’, collect_set(c_id),需要注意的事项
select concat_ws('|', collect_set(c_id)) as num2
from course;
num2 |
---|
03|01|02 |
select s_id, concat_ws('|', collect_set(c_id)) as num1
from score
group by s_id;
s_id | num1 |
---|---|
01 | 01|02|03 |
02 | 01|02|03 |
03 | 01|02|03 |
04 | 01|02|03 |
05 | 01|02 |
06 | 01|03 |
07 | 02|03 |
select *
from (select s_id, concat_ws('|', collect_set(c_id)) as num1
from score
group by s_id) t1
join (select concat_ws('|', collect_set(c_id)) as num2
from course) t2
on t1.num1 = t2.num2;
s_id | s_name | s_birth | s_sex |
---|---|---|---|
02 | 钱电 | 1990-12-21 00:00:00 | 男 |
03 | 孙风 | 1990-05-20 00:00:00 | 男 |
04 | 李云 | 1990-08-06 00:00:00 | 男 |
05 | 周梅 | 1991-12-01 00:00:00 | 女 |
06 | 吴兰 | 1992-03-01 00:00:00 | 女 |
07 | 郑竹 | 1989-07-01 00:00:00 | 女 |
直接关联查询
-- 直接关联查询
select student.*,teacher.t_name
from student
join score on student.s_id = score.s_id
join course on course.c_id = score.c_id
join teacher on course.t_id = teacher.t_id and t_name = '张三';
s_id | s_name | s_birth | s_sex | t_name |
---|---|---|---|---|
01 | 赵雷 | 1990-01-01 00:00:00 | 男 | 张三 |
02 | 钱电 | 1990-12-21 00:00:00 | 男 | 张三 |
03 | 孙风 | 1990-05-20 00:00:00 | 男 | 张三 |
04 | 李云 | 1990-08-06 00:00:00 | 男 | 张三 |
05 | 周梅 | 1991-12-01 00:00:00 | 女 | 张三 |
07 | 郑竹 | 1989-07-01 00:00:00 | 女 | 张三 |
select student.*
from student
where s_id not in (select s_id
from score
join course on score.c_id = course.c_id
join teacher on teacher.t_id = course.t_id and t_name = '张三');
select student.*
from student
left join (select s_id
from score
join course on score.c_id = course.c_id
join teacher on teacher.t_id = course.t_id and t_name = '张三') t1
on student.s_id = t1.s_id
where t1.s_id is null;
s_id | s_name | s_birth | s_sex |
---|---|---|---|
06 | 吴兰 | 1992-03-01 00:00:00 | 女 |
08 | 王菊 | 2017-01-20 00:00:00 | 女 |
select t1.*
from (select s_id,
sum(case when score.c_id = '01' then score.s_score else 0 end) as chinese,
sum(case when score.c_id = '02' then score.s_score else 0 end) as math,
sum(case when score.c_id = '03' then score.s_score else 0 end) as english
from score
group by s_id) t1
join (select sum(case when score.c_id = '01' then score.s_score else 0 end) as chinese,
sum(case when score.c_id = '02' then score.s_score else 0 end) as math,
sum(case when score.c_id = '03' then score.s_score else 0 end) as english
from score
where score.s_id = '04') t2
where t1.chinese > t2.chinese
and t1.math > t2.math
and t1.english > t2.english;
s_id | chinese | math | english |
---|---|---|---|
4 | 50.0 | 30.0 | 20.0 |
s_id | chinese | math | english |
---|---|---|---|
1 | 80.0 | 90.0 | 99.0 |
2 | 70.0 | 60.0 | 80.0 |
3 | 80.0 | 80.0 | 80.0 |
方法1
select student.s_id,
student.s_name,
student.s_sex,
sum(if(c_id = '01', s_score, 0)) as c01_score,
sum(if(c_id = '02', s_score, 0)) as c02_score
from score
join student on score.s_id = student.s_id
group by student.s_id, student.s_name, student.s_sex
having c01_score > c02_score;
s_id | s_name | s_sex | c01_score | c02_score |
---|---|---|---|---|
02 | 钱电 | 男 | 70.0 | 60.0 |
04 | 李云 | 男 | 50.0 | 30.0 |
06 | 吴兰 | 女 | 31.0 | 0.0 |
方法2
select student.s_id,
student.s_name,
t3.c01_score,
t3.c02_score
from student
join (select t1.s_id, t1.c01_score, t2.c02_score
from (select s_id, s_score as c01_score
from score
where c_id = '01') t1
join
(select s_id, s_score as c02_score
from score
where c_id = '02') t2
on t1.s_id = t2.s_id
where t1.c01_score > t2.c02_score) t3
on student.s_id = t3.s_id;
s_id | s_name | s_sex | c01_score | c02_score |
---|---|---|---|---|
02 | 钱电 | 男 | 70.0 | 60.0 |
04 | 李云 | 男 | 50.0 | 30.0 |
寄语:
2种方法都很重要
select s_id,
s_name
from student
where s_id in (select s_id
from score
group by s_id
having min(s_score) > 60
);
s_id | s_name |
---|---|
01 | 赵雷 |
03 | 孙风 |
05 | 周梅 |
07 | 郑竹 |
数据&建表
create table score_cross
(
s_id string,
c_id string,
s_score int
)
insert overwrite table score_cross
values ('01', '01', 80),
('01', '02', 100),
('01', '03', 100),
('02', '02', 80),
('03', '02', 80);
s_id | c_id | s_score |
---|---|---|
01 | 01 | 80 |
01 | 02 | 100 |
01 | 03 | 100 |
02 | 02 | 80 |
03 | 02 | 80 |
无任何连接条件,产生了笛卡尔集合
select *
from score_cross s1, score_cross s2
where s1.c_id<>s2.c_id and s1.s_score=s2.s_score
s_id | c_id | s_score | s_id | c_id | s_score |
---|---|---|---|---|---|
01 | 01 | 80 | 03 | 02 | 80 |
01 | 01 | 80 | 02 | 02 | 80 |
01 | 02 | 100 | 01 | 03 | 100 |
01 | 03 | 100 | 01 | 02 | 100 |
02 | 02 | 80 | 01 | 01 | 80 |
03 | 02 | 80 | 01 | 01 | 80 |
去重
select distinct s1.*
from score_cross s1, score_cross s2
where s1.c_id<>s2.c_id and s1.s_score=s2.s_score
s_id | c_id | s_score |
---|---|---|
02 | 02 | 80 |
01 | 01 | 80 |
01 | 02 | 100 |
01 | 03 | 100 |
03 | 02 | 80 |
select st.*
from (select s_id from score where c_id = '01') t1
join (select s_id from score where c_id = '02') t2
on t1.s_id = t2.s_id
join student st on st.s_id = t1.s_id;
s_id | s_name | s_birth | s_sex |
---|---|---|---|
01 | 赵雷 | 1990-01-01 00:00:00 | 男 |
02 | 钱电 | 1990-12-21 00:00:00 | 男 |
03 | 孙风 | 1990-05-20 00:00:00 | 男 |
04 | 李云 | 1990-08-06 00:00:00 | 男 |
05 | 周梅 | 1991-12-01 00:00:00 | 女 |
另一解题思路:用 in
select student.*
from student
where s_id in (select s_id from score where c_id = '01' and s_id in (select s_id from score where c_id = '02'));
select st.*
from (select s_id from score where c_id = '01') t1
left join (select s_id from score where c_id = '02') t2 on t1.s_id = t2.s_id
left join student st on t1.s_id = st.s_id
where t2.s_id is null;
s_id | s_name | s_birth | s_sex |
---|---|---|---|
06 | 吴兰 | 1992-03-01 00:00:00 | 女 |
另一解题思路:用 not in
不管是mysql中,还是hive中,都不建议使用 not in
select st.*
from score sc
join student st on sc.s_id = st.s_id
where sc.c_id = '01'
and sc.s_id not in (select s_id
from score
where c_id = '02');
select count(1)
from teacher
where t_name like "李%";
res:1
错误做法:
select s_id, round(avg(s_score), 2) as avgscore
from score
where s_score < 60
group by s_id
having count(s_id) >= 2
s_id | avgscore |
---|---|
04 | 33.33 |
06 | 32.50 |
以上方法是错误的
,它只把两门及其以上不及格课程的同学的学号给筛选出来了,但是平均成绩的计算方式是错误的
原表中6号同学只有2门成绩,并且都不及格
添加6号同学的2号课程为85分
正确做法:
select st.s_id,
st.s_name,
round(avg(sc.s_score), 2) as avgScore
from score sc
join (select s_id
from score
where s_score < 60
group by s_id
having count(1) >= 2) t1 on sc.s_id = t1.s_id
join student st on st.s_id = t1.s_id
group by st.s_id, st.s_name;
s_id | s_name | avgscore |
---|---|---|
04 | 李云 | 33.33333 |
06 | 吴兰 | 50.00000 |
order by 中被排序的字段,must be either aggregated, or mentioned in GROUP BY clause
具体解释:
avgScore是被聚合函数应用的字段
c_id 是被分组的字段
select t.t_name,
c.c_name,
round(avg(sc.s_score), 2) as avgScore
from score sc
join course c on sc.c_id = c.c_id
join teacher t on c.t_id = t.t_id
group by t.t_name, c.c_name, c.c_id
order by avgScore desc, c.c_id asc;
c_name | t_name | avgscore |
---|---|---|
数学 | 张三 | 72.67 |
英语 | 王五 | 68.50 |
语文 | 李四 | 64.50 |
上边已经出现过这样类型的题目了,但是这里又出现了,出现的目的是为了告知,数据排序时,如果选择join的方式不对,那么可能无序
。例如你把 left join 换成 join 可以试试
select t1.s_id,
c_name,
t1.s_score,
t1.ranking
from (select s_id,
c_id,
s_score,
row_number() over (partition by c_id order by s_score desc ) as ranking
from score) t1
left join student st on st.s_id = t1.s_id
left join course c on c.c_id = t1.c_id
where t1.ranking >= 2
and t1.ranking <= 3;
s_id | c_name | s_score | ranking |
---|---|---|---|
03 | 语文 | 80.0 | 2 |
05 | 语文 | 76.0 | 3 |
07 | 数学 | 89.0 | 2 |
05 | 数学 | 87.0 | 3 |
07 | 英语 | 98.0 | 2 |
03 | 英语 | 80.0 | 3 |
mysql8.x系列语法更为严格,以下语句会报错:
sql_mode=only_full_group_by
它要求:某字段使用聚合函数后,必须同时使用group by
select student.*,
course.c_name,
max(score.s_score) as maxscore
from student
join score on student.s_id = score.s_id
join course on score.c_id = course.c_id
join teacher on teacher.t_id = course.t_id and t_name = '张三';
s_id | s_name | s_birth | s_sex | c_name | maxscore |
---|---|---|---|---|---|
01 | 赵雷 | 1990-01-01 00:00:00 | 男 | 数学 | 90.0 |
mysql8.x系列语法更为严格,以下语句会报错:
sql_mode=only_full_group_by
select student.s_name,
t1.mathmaxscore,
sum(case when score.c_id = '01' then score.s_score else 0 end) as chinese,
sum(case when score.c_id = '03' then score.s_score else 0 end) as english
from score
join (select s_id,
max(s_score) as mathmaxscore
from score
join course on score.c_id = course.c_id
join teacher on teacher.t_id = course.t_id and teacher.t_name = '张三') t1
on score.s_id = t1.s_id
join student on student.s_id = score.s_id;
之所以不用in,是因为用了以后无法确定那门课是最高成绩,故:用join比较合适
s_name | mathmaxscore | chinese | english |
---|---|---|---|
赵雷 | 90.0 | 80.0 | 99.0 |
select *
from student
where s_birth like '1990%';
s_id | s_name | s_birth | s_sex |
---|---|---|---|
01 | 赵雷 | 1990-01-01 | 男 |
02 | 钱电 | 1990-12-21 | 男 |
03 | 孙风 | 1990-05-20 | 男 |
04 | 李云 | 1990-08-06 | 男 |
08 | 王菊 | 1990-01-20 | 女 |
-- 张三生日:2020-05-04
-- 李四生日:2020-03-04
-- 当前日期:2022-04-04
-- 通常计算年龄的方式(张三,李四) 2022-2020 = 2岁
select s_name, s_birth, year(current_date) - year(s_birth) as age
from student;
s_name | s_birth | age |
---|---|---|
赵雷 | 1990-01-01 00:00:00 | 32 |
钱电 | 1990-12-21 00:00:00 | 32 |
孙风 | 1990-05-20 00:00:00 | 32 |
李云 | 1990-08-06 00:00:00 | 32 |
周梅 | 1991-12-01 00:00:00 | 31 |
吴兰 | 1992-03-01 00:00:00 | 30 |
郑竹 | 1989-07-01 00:00:00 | 33 |
王菊 | 1990-01-20 00:00:00 | 32 |
-- 有时候较真计算年龄:张三实际年龄2岁少1个月:2022-2020-1=1岁
-- 李四实际年龄2岁多1个月:2022-2020-0=2岁
select s_name,
s_birth,
(year(current_date) - year(s_birth) - (case
when month(CURRENT_DATE) < month(s_birth) then 1
when month(CURRENT_DATE) = month(s_birth) and
day(CURRENT_DATE) < day(s_birth) then 1
else 0 end)
) as age
from student;
s_name | s_birth | age |
---|---|---|
赵雷 | 1990-01-01 00:00:00 | 32 |
钱电 | 1990-12-21 00:00:00 | 31 |
孙风 | 1990-05-20 00:00:00 | 32 |
李云 | 1990-08-06 00:00:00 | 32 |
周梅 | 1991-12-01 00:00:00 | 30 |
吴兰 | 1992-03-01 00:00:00 | 30 |
郑竹 | 1989-07-01 00:00:00 | 33 |
王菊 | 1990-01-20 00:00:00 | 32 |
select *
from student
where weekofyear(current_date) = weekofyear(s_birth);
select *
from student
where weekofyear(CURRENT_DATE) + 1 = weekofyear(s_birth);
--方法1
select s_name, s_sex, s_birth
from student
where substring(s_birth, 6, 2) = '12';
--方法2
select s_name, s_sex, s_birth
from student
where month(s_birth) = '12';
s_name | s_sex | s_birth |
---|---|---|
钱电 | 男 | 1990-12-21 |
周梅 | 女 | 1991-12-01 |
order by 中被排序的字段,must be either aggregated, or mentioned in GROUP BY clause
(例如查询不同老师所教课程的平均成绩)create table student
(
s_id string,
s_name string,
s_birth string,
s_sex string
);
create table course
(
c_id string,
c_name string,
t_id string
);
create table teacher
(
t_id string,
t_name string
);
create table score
(
s_id string,
c_id string,
s_score int
);
insert into student (s_id, s_name, s_birth, s_sex) values ('01', '赵雷', '1990-01-01 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('02', '钱电', '1990-12-21 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('03', '孙风', '1990-05-20 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('04', '李云', '1990-08-06 00:00:00', '男');
insert into student (s_id, s_name, s_birth, s_sex) values ('05', '周梅', '1991-12-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('06', '吴兰', '1992-03-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('07', '郑竹', '1989-07-01 00:00:00', '女');
insert into student (s_id, s_name, s_birth, s_sex) values ('08', '王菊', '1990-01-20 00:00:00', '女');
insert into score (s_id, c_id, s_score) values ('01', '01', 80.0);
insert into score (s_id, c_id, s_score) values ('01', '02', 90.0);
insert into score (s_id, c_id, s_score) values ('01', '03', 99.0);
insert into score (s_id, c_id, s_score) values ('02', '01', 70.0);
insert into score (s_id, c_id, s_score) values ('02', '02', 60.0);
insert into score (s_id, c_id, s_score) values ('02', '03', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '01', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '02', 80.0);
insert into score (s_id, c_id, s_score) values ('03', '03', 80.0);
insert into score (s_id, c_id, s_score) values ('04', '01', 50.0);
insert into score (s_id, c_id, s_score) values ('04', '02', 30.0);
insert into score (s_id, c_id, s_score) values ('04', '03', 20.0);
insert into score (s_id, c_id, s_score) values ('05', '01', 76.0);
insert into score (s_id, c_id, s_score) values ('05', '02', 87.0);
insert into score (s_id, c_id, s_score) values ('06', '01', 31.0);
insert into score (s_id, c_id, s_score) values ('06', '03', 34.0);
insert into score (s_id, c_id, s_score) values ('07', '02', 89.0);
insert into score (s_id, c_id, s_score) values ('07', '03', 98.0);
insert into course (c_id, c_name, t_id) values ('01', '语文', '02');
insert into course (c_id, c_name, t_id) values ('02', '数学', '01');
insert into course (c_id, c_name, t_id) values ('03', '英语', '03');
insert into teacher (t_id, t_name) values ('01', '张三');
insert into teacher (t_id, t_name) values ('02', '李四');
insert into teacher (t_id, t_name) values ('03', '王五');
sql 面试题-求职