经典sql50题
sql练习的经典习题。需要注意47,48的时间问题,不同年中的同月同日,并不一定是同一周。
自行练习完,在对比学习,效果更佳哦。
建立练题表
# 学生表
create table stu(
s_id varchar(10) primary key,
s_name varchar(10) not null,
s_age date not null,
s_sex varchar(10) default '未知'
);
# 课程表
create table co(
c_id varchar(10) primary key,
c_name varchar(10) not null,
t_id varchar(102) not null
);
# 教师表
create table te(
t_id varchar(10) primary key,
t_name varchar(10) not null
);
# 成绩表
create table sc(
s_id varchar(10) not null,
c_id varchar(10) not null,
score int not null
);
插入数据
# stu表数据
insert into stu values
('01','赵雷','1990-01-01','男'),
('02','钱电','1990-12-21','男'),
('03','孙风','1990-05-20','男'),
('04','李云','1990-08-06','男'),
('05','周梅','1991-12-01','女'),
('06','吴兰','1992-03-01','女'),
('07','王菊','1990-01-20','女');
# co表数据
insert into co values
('01','语文','02'),
('02','数学','01'),
('03','英语','03');
# te表数据
insert into te values
('01','张三'),
('02','李四'),
('03','王五');
# sc表数据
insert into sc values
('01','01',80),
('01','02',90),
('01','03',99),
('02','01',70),
('02','02',50),
('02','03',80),
('03','01',80),
('03','02',80),
('03','03',80),
('04','01',50),
('04','02',30),
('04','03',20),
('05','01',76),
('05','02',87),
('06','01',31),
('06','03',34),
('07','02',89),
('07','03',98);
1~10题
# 1.查询"01"课程比"02"课程成绩高的学生的信息及课程分数
# 方法1
select s_name, s_age, s_sex, t3.C01_score, t3.C02_score
from stu,
(select t1.s_id,t1.score as C01_score,t2.score as C02_score from
(select s_id,score from sc
where c_id = '01') as t1
,
(select s_id, score from sc
where c_id = '02') as t2
where t1.s_id = t2.s_id and t1.score > t2.score) as t3
where stu.s_id = t3.s_id;
# 方法2
select stu.*, b.score as 01_score, c.score as 02_score from
stu
join sc b on stu.s_id=b.s_id and b.c_id='01'
left join sc c on stu.s_id = c.s_id and c.c_id='02'
where b.score> c.score;
#2.查询"01"课程比"02"课程成绩低的学生的信息及课程分数
# 方法1
select s_name,s_age,s_sex,t3.C01_score ,t3.C02_score
from stu,
(select t1.s_id,t1.score as C01_score,t2.score as C02_score from
(select s_id,score from sc
where c_id = '01') as t1
,
(select s_id,score from sc
where c_id = '02') as t2
where t1.s_id = t2.s_id and t1.score < t2.score) as t3
where stu.s_id = t3.s_id ;
# 方法2
select stu.*, b.score as 01_score, c.score as 02_score from
stu
join sc b on stu.s_id=b.s_id and b.c_id='01'
left join sc c on stu.s_id = c.s_id and c.c_id='02'
where b.score < c.score;
#3、查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
# 方一
select stu.s_id,s_name,round(t1.平均成绩,2)
from stu,
(select s_id, avg(score) as '平均成绩' from sc
group by s_id
having avg(score) >= 60) as t1
where stu.s_id = t1.s_id;
# 方二
select stu.s_id,s_name,round(avg(sc.score),2) from stu
right join sc on stu.s_id = sc.s_id
group by sc.s_id
having avg(sc.score) >= 60;
#4、查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩
# 方1
select stu.s_id,s_name,t1.平均成绩
from stu,
(select s_id,avg(score) as '平均成绩' from sc
group by s_id
having avg(score) < 60) as t1
where stu.s_id = t1.s_id;
# 方2
select stu.s_id,s_name,round(avg(sc.score),2) from stu
left join sc on stu.s_id = sc.s_id
group by sc.s_id
having avg(sc.score) < 60;
#5、查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩
select stu.s_id,s_name,count(score) as '选课总数',sum(score) as '总成绩' from stu
left join sc on stu.s_id = sc.s_id
group by stu.s_id;
#6、查询"李"姓老师的数量
select count(t_id) as '李姓老师数量' from te
where t_name like '李%';
#7、查询学过"张三"老师授课的同学的信息
select stu.s_id,s_name,s_age,s_sex from stu,
(select s_id from sc,
(select c_id from co
left join te on co.t_id = te.t_id
where t_name = '张三') t1
where sc.c_id = t1.c_id) t2
where stu.s_id = t2.s_id;
#8、查询没学过"张三"老师授课的同学的信息
select stu.s_id,s_name,s_age,s_sex from stu
where stu.s_id not in
(select s_id from sc,
(select c_id from co
left join te on co.t_id = te.t_id
where t_name = '张三') t1
where sc.c_id = t1.c_id);
#9、查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息
# 方1
select s_id,s_name,s_age,s_sex from stu
where s_id in
(select s_id from sc
where c_id = '02' and s_id in
(select s_id from sc
where c_id = '01'));
# 方2
select a.* from
stu a, sc b, sc c
where a.s_id = b.s_id and a.s_id = c.s_id and b.c_id='01' and c.c_id='02';
#10、查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息
# 方1
select s_id,s_name,s_age,s_sex from stu
where s_id in
(select s_id from sc
where c_id = '01' and s_id not in
(select s_id from sc
where c_id = '02'));
11~20题
#11、查询没有学全所有课程的同学的信息
select s_id,s_name,s_age,s_sex from stu
where s_id in
(select s_id from sc
group by s_id
having count(c_id) < (select count(c_id) from co));
#12、查询至少有一门课与学号为"01"的同学所学相同的同学的信息
select s_id,s_name,s_age,s_sex from stu
where s_id in
(select distinct s_id from sc
where s_id != '01' and c_id in
(select c_id from sc
where s_id = '01'));
#13、查询和"01"号的同学学习的课程完全相同的其他同学的信息
select s_id,s_name,s_age,s_sex from stu
where s_id in
(select s_id from
(select s1.s_id from sc s1 join sc s2 on s1.c_id=s2.c_id where s1.s_id<>'01' and s2.s_id ='01') as t1
group by s_id having count(s_id) = (select count(c_id) from sc where s_id = '01'));
#14、查询没学过"张三"老师讲授的任一门课程的学生姓名
select stu.s_id,s_name,s_age,s_sex from stu
where stu.s_id not in
(select s_id from sc,
(select c_id from co
left join te on co.t_id = te.t_id
where t_name = '张三') t1
where sc.c_id = t1.c_id);
#15、查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
select stu.s_id,s_name,平均成绩 from stu
right join
(select s_id,avg(score) as '平均成绩' from sc
where score < 60
group by s_id having count(s_id) >= 2) t1
on stu.s_id = t1.s_id;
#16、检索"01"课程分数小于60,按分数降序排列的学生信息
select t1.s_id,s_name,s_age,s_sex,score from stu
right join
(select s_id,score from sc
where c_id = '01' and score < 60) t1
on stu.s_id = t1.s_id
order by score DESC;
#17、按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
select a.s_id 学生编号, a.s_name 学生姓名,
max(case c.c_name when '语文' then b.score else 0 end) 语文,
max(case c.c_name when '数学' then b.score else 0 end) 数学,
max(case c.c_name when '英语' then b.score else 0 end) 英语,
cast(avg(b.score) as decimal(18,2)) 平均分
from stu a
left join sc b on a.s_id = b.s_id
left join co c on b.c_id = c.c_id
group by a.s_id
order by 平均分 desc;
#18、查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,最高分,最低分,平均分,
#及格率,中等率,优良率,优秀率
# 及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
select co.c_id as '课程ID',c_name as '课程nam',
max(score) as '最高分',
min(score) as '最低分',
cast(avg(score) as decimal(18,2)) as '平均分',
cast(((select count(score) from sc where score >=60 and c_id = co.c_id)/count(score))as decimal(18,2)) as '及格率',
cast(((select count(score) from sc where score >=70 and score <80 and c_id = co.c_id)/count(score))as decimal(18,2)) as '中等率',
cast(((select count(score) from sc where score >=80 and score <90 and c_id = co.c_id)/count(score))as decimal(18,2)) as '优良率',
cast(((select count(score) from sc where score >=90 and c_id = co.c_id)/count(score))as decimal(18,2)) as '优秀率'
from co
left join sc on co.c_id = sc.c_id
group by co.c_id;
#19、按各科成绩进行排序,并显示排名
# 方1 计算人数 分科排名
select t1.*,(select count(score) from sc where c_id = t1.c_id and score >= t1.score) as '排名'
from sc as t1
order by c_id,score DESC;
# 方2 会全排
select a.s_id,a.c_id,
@i:=@i +1 as i保留排名,
@k:=(case when @score=a.score then @k else @i end) as rank不保留排名,
@score:=a.score as score
from
(select s_id,c_id,score from sc GROUP BY s_id,c_id,score ORDER BY score DESC) a,
(select @k:=0,@i:=0,@score:=0) s;
#20、查询学生的总成绩并进行排名
select s_id,s_name,s_age,s_sex,总成绩,
@i:=@i+1 as rank
from
(select stu.s_id,s_name,s_age,s_sex,
sum(score) as '总成绩'
from stu
left join sc as t1 on stu.s_id = t1.s_id
group by t1.s_id
order by 总成绩 desc) s,
(select @i:=0) a;
21~30题
#21、查询不同老师所教不同课程平均分从高到低显示
select te.t_name, co.c_name, round(avg(score),2) from te
left join co on te.t_id = co.t_id
left join sc on co.c_id = sc.c_id
group by te.t_name, co.c_name
order by avg(score) desc;
#22、查询所有课程的成绩第2名到第3名的学生信息及该课程成绩
create view result3 as
SELECT stu.*, co.c_name, sc.score FROM stu,sc,co WHERE stu.s_id = sc.s_id AND sc.c_id = co.c_id GROUP BY sc.c_id,sc.s_id;
(select * from result3 where c_name = '语文' order by score desc limit 1,2)
union
(select * from result3 where c_name = '数学' order by score desc limit 1,2)
union
(select * from result3 where c_name = '英语' order by score desc limit 1,2);
#23、统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比
select sc.c_id,co.c_name,
(select count(c_id) from sc sc1 where sc.c_id = sc1.c_id and score>=85) as '[100-85]',
cast(((select count(c_id) from sc sc1 where sc.c_id = sc1.c_id and score>=85)/(select count(c_id) from sc sc1 where sc.c_id = sc1.c_id)*100)as decimal(18,2))as '[100-85](%)',
(select count(c_id) from sc sc1 where sc.c_id = sc1.c_id and score between 70 and 85) as '[85-70]',
cast(((select count(c_id) from sc sc1 where sc.c_id = sc1.c_id and score between 70 and 85)/(select count(c_id) from sc sc1 where sc.c_id = sc1.c_id)*100)as decimal(18,2))as '[85-70](%)',
(select count(c_id) from sc sc1 where sc.c_id = sc1.c_id and score between 60 and 70) as '[70-60]',
cast(((select count(c_id) from sc sc1 where sc.c_id = sc1.c_id and score between 60 and 70)/(select count(c_id) from sc sc1 where sc.c_id = sc1.c_id)*100)as decimal(18,2))as '[70-60](%)',
(select count(c_id) from sc sc1 where sc.c_id = sc1.c_id and score < 60) as '[0-60]',
cast(((select count(c_id) from sc sc1 where sc.c_id = sc1.c_id and score < 60)/(select count(c_id) from sc sc1 where sc.c_id = sc1.c_id)*100)as decimal(18,2))as '[0-60](%)'
from sc,co
where sc.c_id = co.c_id
group by sc.c_id;
#24、查询学生平均成绩及其名次
select b.*, @j:=@j+1 as '排名'
from
(SELECT stu.s_id,stu.s_name,avg(sc.score) AS score
FROM stu,sc
WHERE stu.s_id = sc.s_id
GROUP BY sc.s_id
ORDER BY avg(sc.score) DESC) as b,
(SELECT @j := 0 ) sdcore;
#25、查询各科成绩前三名的记录
create view result4 as
select stu.*,co.c_name,sc.score from stu,co,sc
where stu.s_id = sc.s_id and sc.c_id = co.c_id
group by co.c_name,stu.s_id;
select t1.c_name,t1.s_name,t1.score from
result4 as t1
left join result4 as t2
on t1.c_name = t2.c_name and t2.score > t1.score
group by t1.c_name,t1.s_id
having count(t2.c_name) < 3
order by t1.c_name,t1.score desc;
#26、查询每门课程被选修的学生数
select co.c_name,count(score) from co
left join sc on co.c_id = sc.c_id
group by co.c_name;
#27、查询出只有两门课程的全部学生的学号和姓名
select sc.s_id,stu.s_name from sc,stu
where sc.s_id = stu.s_id
group by sc.s_id
having count(score) = 2;
#28、查询男生、女生人数
# 方1
select sum(case stu.s_sex when '男' then 1 else 0 end) 男生,
sum(case stu.s_sex when '女' then 1 else 0 end) 女生
from stu;
# 方2
select s_sex as '性别',COUNT(1) as '人数'
from stu
group by s_sex;
#29、查询名字中含有"风"字的学生信息
select * from stu
where s_name like '%风%';
#30、查询同名同性学生名单,并统计同名人数
select s_name,s_sex,count(s_name)
from stu
group by s_name,s_sex
having count(s_name) >1;
31~40题
#31、查询1990年出生的学生名单(注:Student表中Sage列的类型是datetime)
select * from stu
where year(s_age) = 1990;
#32、查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号
select co.c_name,avg(score) from co
left join sc on co.c_id = sc.c_id
group by co.c_id
order by avg(score) desc,co.c_id asc;
#33、查询平均成绩大于等于85的所有学生的学号、姓名和平均成绩
select stu.s_id,stu.s_name,avg(score) from stu,sc
where stu.s_id = sc.s_id
group by stu.s_id
having avg(score)>=85;
#34、查询课程名称为"数学",且分数低于60的学生姓名和分数
select co.c_name,s_name,score from co
left join sc on co.c_id = sc.c_id
left join stu on sc.s_id = stu.s_id
where c_name = '数学' and score < 60;
#35、查询所有学生的课程及分数情况;
# 方1 堆叠方式
select s_name,c_name,score from stu
left join sc on stu.s_id = sc.s_id
left join co on sc.c_id = co.c_id
order by s_name,c_name,score desc;
# 方2 展开方式
select a.s_id 学生编号, a.s_name 学生姓名,
max(case c.c_name when '语文' then b.score else 0 end) 语文,
max(case c.c_name when '数学' then b.score else 0 end) 数学,
max(case c.c_name when '英语' then b.score else 0 end) 英语,
cast(sum(b.score) as decimal(18,2)) 总分
from stu a
left join sc b on a.s_id = b.s_id
left join co c on b.c_id = c.c_id
group by a.s_id
order by 总分 desc;
#36、查询任何一门课程成绩在70分以上的姓名、课程名称和分数;
select s_name,c_name,score from sc
left join stu on sc.s_id = stu.s_id
left join co on sc.c_id = co.c_id
where score > 70;
#37、查询不及格的课程
select s_name,c_name,score from sc
left join stu on sc.s_id = stu.s_id
left join co on sc.c_id = co.c_id
where score < 60;
#38、查询课程编号为01且课程成绩在80分以上的学生的学号和姓名;
select stu.s_id,s_name,c_name,score from co
left join sc on sc.c_id = co.c_id
left join stu on sc.s_id = stu.s_id
where co.c_id = '01' and score >=80;
#39、求每门课程的学生人数
select c_name,count(sc.c_id) from co,sc
where co.c_id = sc.c_id
group by co.c_id;
#40、查询选修"张三"老师所授课程的学生中,成绩最高的学生信息及其成绩
select stu.s_id,s_name,s_age,s_sex,c_name,score from te
left join co on te.t_id = co.t_id
left join sc on co.c_id = sc.c_id
left join stu on sc.s_id = stu.s_id
where t_name = '张三 '
order by score desc
limit 1;
41~50题
#41、查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
select distinct sc.s_id,sc.c_id,sc.score from sc
left join sc as sc1 on sc.c_id != sc1.c_id
where sc.score = sc1.score;
#42、查询每门功成绩最好的前两名
# 方1
create view result5 as
select stu.s_id,s_name,c_name,score from sc
left join co on sc.c_id = co.c_id
left join stu on sc.s_id =stu.s_id;
select a.c_name,a.s_id,a.s_name,a.score from result5 as a
left join result5 as b on a.c_name = b.c_name and b.score > a.score
group by a.c_name,a.s_id,a.s_name
having count(b.s_id) < 2;
# 方2
select co.c_name, stu.s_name ,a.score from sc a
left join co on a.c_id = co.c_id
left join stu on a.s_id = stu.s_id
where (select COUNT(1) from sc b where b.c_id=a.c_id and b.score>=a.score) <=2
ORDER BY a.c_id;
#43、统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
select c_id,count(1) from sc
group by c_id
having count(1) > 5
order by count(1) desc, c_id;
#44、检索至少选修两门课程的学生学号
select s_id, count(1) from sc
group by s_id
having count(1)>=2;
#45、查询选修了全部课程的学生信息
select stu.s_id,s_name,s_age,s_sex from stu
right join
(select s_id from sc
group by s_id
having count(1) = (select count(1) from co)) t1
on stu.s_id = t1.s_id;
#46、查询各学生的年龄
# 判断生日是否已过
select s_name, (year(curdate())-year(s_age)-
(case when DATE_FORMAT(NOW(),'%m%d')>DATE_FORMAT(s_age,'%m%d') then 0 else 1 end)) as age
from stu;
#47、查询本周过生日的学生
# 剔除年的影响,不同年的同一日不一定是同一周
select s_name s_age from stu
where weekofyear(makedate(year(curdate()),dayofyear(s_age))) = weekofyear(curdate());
#48、查询下周过生日的学生
# 剔除年的影响,不同年的同一日不一定是同一周
select s_name s_age from stu
where weekofyear(makedate(year(curdate()),dayofyear(s_age))) - weekofyear(curdate()) = 1;
#49、查询本月过生日的学生
select s_id,s_name,s_age from stu
where month(curdate()) = month(s_age);
#50、查询下月过生日的学生
select s_id,s_name,s_age from stu
where month(curdate()) - month(s_age) = -1;