50道SQL練習題及答案與詳細分析(MySQL)


50道SQL練習題及答案與詳細分析(MySQL)

網上的經典50到SQL題,經過一陣子的半抄帶做,基於個人理解使用MySQL重新完成一遍,感覺個人比較喜歡用join,聯合查詢較少

希望與大家一起學習研究改進,歡迎指點


數據表介紹

--1.學生表
Student(SId,Sname,Sage,Ssex)
--SId 學生編號,Sname 學生姓名,Sage 出生年月,Ssex 學生性別

--2.課程表
Course(CId,Cname,TId)
--CId 課程編號,Cname 課程名稱,TId 教師編號

--3.教師表
Teacher(TId,Tname)
--TId 教師編號,Tname 教師姓名

--4.成績表

SC(SId,CId,score)
--SId 學生編號,CId 課程編號,score 分數

學生表 Student

create table Student(SId varchar(10),Sname varchar(10),Sage datetime,Ssex varchar(10));
insert into Student values('01' , '趙雷' , '1990-01-01' , '男');
insert into Student values('02' , '錢電' , '1990-12-21' , '男');
insert into Student values('03' , '孫風' , '1990-12-20' , '男');
insert into Student values('04' , '李雲' , '1990-12-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吳蘭' , '1992-01-01' , '女');
insert into Student values('07' , '鄭竹' , '1989-01-01' , '女');
insert into Student values('09' , '張三' , '2017-12-20' , '女');
insert into Student values('10' , '李四' , '2017-12-25' , '女');
insert into Student values('11' , '李四' , '2012-06-06' , '女');
insert into Student values('12' , '趙六' , '2013-06-13' , '女');
insert into Student values('13' , '孫七' , '2014-06-01' , '女');

科目表 Course

create table Course(CId varchar(10),Cname nvarchar(10),TId varchar(10));
insert into Course values('01' , '語文' , '02');
insert into Course values('02' , '數學' , '01');
insert into Course values('03' , '英語' , '03');

教師表Teacher

create table Teacher(TId varchar(10),Tname varchar(10));
insert into Teacher values('01' , '張三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');

成績表 SC

create table SC(SId varchar(10),CId varchar(10),score decimal(18,1));
insert into SC values('01' , '01' , 80);
insert into SC values('01' , '02' , 90);
insert into SC values('01' , '03' , 99);
insert into SC values('02' , '01' , 70);
insert into SC values('02' , '02' , 60);
insert into SC values('02' , '03' , 80);
insert into SC values('03' , '01' , 80);
insert into SC values('03' , '02' , 80);
insert into SC values('03' , '03' , 80);
insert into SC values('04' , '01' , 50);
insert into SC values('04' , '02' , 30);
insert into SC values('04' , '03' , 20);
insert into SC values('05' , '01' , 76);
insert into SC values('05' , '02' , 87);
insert into SC values('06' , '01' , 31);
insert into SC values('06' , '03' , 34);
insert into SC values('07' , '02' , 89);
insert into SC values('07' , '03' , 98);

練習題目

  1. 查詢" 01 "課程比" 02 "課程成績高的學生的信息及課程分數
    1.1 查詢同時存在" 01 "課程和" 02 "課程的情況
    1.2 查詢存在" 01 "課程但可能不存在" 02 "課程的情況(不存在時顯示為 null )
    1.3 查詢不存在" 01 "課程但存在" 02 "課程的情況
  2. 查詢平均成績大於等於 60 分的同學的學生編號和學生姓名和平均成績
  3. 查詢在 SC 表存在成績的學生信息
  4. 查詢所有同學的學生編號、學生姓名、選課總數、所有課程的總成績(沒成績的顯示為 null )
    4.1 查有成績的學生信息
  5. 查詢「李」姓老師的數量
  6. 查詢學過「張三」老師授課的同學的信息
  7. 查詢沒有學全所有課程的同學的信息
  8. 查詢至少有一門課與學號為" 01 "的同學所學相同的同學的信息
  9. 查詢和" 01 "號的同學學習的課程 完全相同的其他同學的信息
  10. 查詢沒學過"張三"老師講授的任一門課程的學生姓名
  11. 查詢兩門及其以上不及格課程的同學的學號,姓名及其平均成績
  12. 檢索" 01 "課程分數小於 60,按分數降序排列的學生信息
  13. 按平均成績從高到低顯示所有學生的所有課程的成績以及平均成績
  14. 查詢各科成績最高分、最低分和平均分:
    以如下形式顯示:課程 ID,課程 name,最高分,最低分,平均分,及格率,中等率,優良率,優秀率
    及格為>=60,中等為:70-80,優良為:80-90,優秀為:>=90
    要求輸出課程號和選修人數,查詢結果按人數降序排列,若人數相同,按課程號升序排列
  15. 按各科成績進行排序,並顯示排名, Score 重復時保留名次空缺
    15.1 按各科成績進行排序,並顯示排名, Score 重復時合並名次
  16. 查詢學生的總成績,並進行排名,總分重復時保留名次空缺
    16.1 查詢學生的總成績,並進行排名,總分重復時不保留名次空缺
  17. 統計各科成績各分數段人數:課程編號,課程名稱,[100-85],[85-70],[70-60],[60-0] 及所占百分比
  18. 查詢各科成績前三名的記錄
  19. 查詢每門課程被選修的學生數
  20. 查詢出只選修兩門課程的學生學號和姓名
  21. 查詢男生、女生人數
  22. 查詢名字中含有「風」字的學生信息
  23. 查詢同名同性學生名單,並統計同名人數
  24. 查詢 1990 年出生的學生名單
  25. 查詢每門課程的平均成績,結果按平均成績降序排列,平均成績相同時,按課程編號升序排列
  26. 查詢平均成績大於等於 85 的所有學生的學號、姓名和平均成績
  27. 查詢課程名稱為「數學」,且分數低於 60 的學生姓名和分數
  28. 查詢所有學生的課程及分數情況(存在學生沒成績,沒選課的情況)
  29. 查詢任何一門課程成績在 70 分以上的姓名、課程名稱和分數
  30. 查詢不及格的課程
  31. 查詢課程編號為 01 且課程成績在 80 分以上的學生的學號和姓名
  32. 求每門課程的學生人數
  33. 成績不重復,查詢選修「張三」老師所授課程的學生中,成績最高的學生信息及其成績
  34. 成績有重復的情況下,查詢選修「張三」老師所授課程的學生中,成績最高的學生信息及其成績
  35. 查詢不同課程成績相同的學生的學生編號、課程編號、學生成績
  36. 查詢每門功成績最好的前兩名
  37. 統計每門課程的學生選修人數(超過 5 人的課程才統計)。
  38. 檢索至少選修兩門課程的學生學號
  39. 查詢選修了全部課程的學生信息
  40. 查詢各學生的年齡,只按年份來算
  41. 按照出生日期來算,當前月日 < 出生年月的月日則,年齡減一
  42. 查詢本周過生日的學生
  43. 查詢下周過生日的學生
  44. 查詢本月過生日的學生
  45. 查詢下月過生日的學生

答案

1 查詢" 01 "課程比" 02 "課程成績高的學生的信息及課程分數

select * from student
where sid in
	(select a.sid from sc a
    join sc b on a.sid = b.sid
    where a.cid = 01
    and b.cid = 02
    and a.score > b.score)

1.1 查詢同時存在" 01 "課程和" 02 "課程的情況

select * from sc a
join sc b on a.sid = b.sid
where a.cid = 01
and b.cid = 02

1.2 查詢存在" 01 "課程但可能不存在" 02 "課程的情況(不存在時顯示為 null )

select * from 
(select * from sc where cid = 01)a
left join
(select * from sc where cid = 02)b
on a.sid = b.sid

1.3 查詢不存在" 01 "課程但存在" 02 "課程的情況

select * from sc
where sc.sid not in
	(select a.sid from sc a where a.cid = 01)
    and sc.cid =02

2 查詢平均成績大於等於 60 分的同學的學生編號和學生姓名和平均成績

select s.sid,s.sname,avg(sc.score) 平均成績
from student s
join sc on s.sid = sc.sid
group by s.sid
having avg(sc.score) > 60

3 查詢在 SC 表存在成績的學生信息

select distinct s.* from student s
join sc on s.sid = sc.sid

4 查詢所有同學的學生編號、學生姓名、選課總數、所有課程的總成績(沒成績的顯示為 null )

select s.sid, s.sname, count(sc.cid), sum(sc.score)
from student s left join sc
on s.sid = sc.sid
group by s.sid

4.1 查有成績的學生信息

select s.* from student s
join sc on s.sid = sc.sid
group by s.sid
having count(sc.cid) > 0
select s.* from student s
where s.sid in (select sc.sid
               from sc where sc.sid = s.sid)

5 查詢「李」姓老師的數量

select count(t.tid) from Teacher t
where t.tname like '李%'

6 查詢學過「張三」老師授課的同學的信息

select s.* from student s
join sc on s.sid = sc.sid
join course c  on c.cid = sc.cid
join teacher t on c.tid = t.tid
where t.tname = '張三'

7 查詢沒有學全所有課程的同學的信息

# 如果包含所有課程都未學的,去掉count(sc.cid) > 0
select s.* from student s
left join sc on s.sid = sc.sid
group by s.sid 
having count(sc.cid) > 0 and
count(sc.cid) < (select count(*) from course)

8 查詢至少有一門課與學號為" 01 "的同學所學相同的同學的信息

select distinct s.* from student s
join sc a on s.sid = a.sid
where a.cid in(
    select sc.cid from sc
    where sc.sid = 01)

9 查詢和" 01 "號的同學學習的課程 完全相同的其他同學的信息

# 這里的總感覺可以優化,思路是第8題加上學的科數也相等
select distinct s.* from student s
join sc a on s.sid = a.sid
where a.cid in(
    select sc.cid from sc
    where sc.sid = 01)
group by s.sid
having count(a.cid) = (select count(b.cid) from sc b where sc.sid =01)

10 查詢沒學過"張三"老師講授的任一門課程的學生姓名

select student.* from student
where student.sid not in(
 	select s.sid from student s
    join sc on s.sid = sc.sid
    join course c on sc.cid = c.cid
    join teacher t on c.tid = t.tid
    where t.tname = '張三')

11 查詢兩門及其以上不及格課程的同學的學號,姓名及其平均成績

select s.sname,s.sid,avg(sc.score)
from student s join sc
on s.sid = sc.sid
where sc.score < 60
group by s.sid
having count(sc.cid) >=2

12 檢索" 01 "課程分數小於 60,按分數降序排列的學生信息

select s.*,sc.score from student s
join sc on s.sid = sc.sid
where sc.cid = 01
and sc.score < 60
order by sc.score desc

13 按平均成績從高到低顯示所有學生的所有課程的成績以及平均成績

select sid,
sum(case when sc.cid = 01 then sc.score else null end) as score_01,
sum(case when sc.cid = 02 then sc.score else null end) as score_02,
sum(case when sc.cid = 03 then sc.score else null end) as score_03,
avg(score) from sc
group by sid
order by avg(score) desc

14 查詢各科成績最高分、最低分和平均分:

以如下形式顯示:課程 ID,課程 name,最高分,最低分,平均分,及格率,中等率,優良率,優秀率

及格為>=60,中等為:70-80,優良為:80-90,優秀為:>=90

要求輸出課程號和選修人數,查詢結果按人數降序排列,若人數相同,按課程號升序排列

select sc.cid,c.cname as 課程名稱,count(sc.cid) 選修人數,max(sc.score)最高分,
min(sc.score)最低分,avg(sc.score),
(sum(case when score >= 60 then 1 else 0 end)/ count(sc.score)) as 及格率,
(sum(case when score >= 70 and score < 80 then 1 else 0 end)/ count(sc.score)) as 中等,
(sum(case when score >= 80 and score < 90 then 1 else 0 end)/count(sc.score)) as 優良,
(sum(case when score >= 90 then 1 else 0 end)/count(sc.score)) as 優秀
from sc join course c on sc.cid = c.cid
group by sc.cid 
order by count(sc.cid), cid

15 個人對於分組排序,對變量使用還不是很了解

下面第一個代碼詳情

# 這里的函數應該是MySQL8.0后的才有
select sid,cid,score,
row_number() over(partition by cid order by score desc) as 'rank',
RANK() over(partition by cid order by score desc) as 'rank2',
DENSE_RANK() over(partition by cid order by score desc) as 'rank3'
from sc
# 這個是按各科成績排序,排名,score重復 沒有進行操作
select cid,sid, score,ranks
from (select cid,sid,score,@ranks := if(@cid = cid,@ranks+1,1)ranks,
@cid :=cid 
from sc,(select @cid:=null,@ranks :=0)temp
order by cid,sc.score desc) t

15 按各科成績進行排序,並顯示排名, Score 重復時保留名次空缺

# 空值暫時不會 好像有case when + 變量函數

15.1 按各科成績進行排序,並顯示排名, Score 重復時合並名次

# 這里和上面的例子差不多
select a.cid, a.sid, a.score, count(b.score)+1 as ranks
from sc as a 
left join sc as b 
on a.score<b.score and a.cid = b.cid
group by a.cid, a.sid,a.score
order by a.cid, ranks

16 查詢學生的總成績,並進行排名,總分重復時保留名次空缺

# 又是空缺~~  其實吧,空缺意義不大應該是這樣的哈哈哈  后面補充

16.1 查詢學生的總成績,並進行排名,總分重復時不保留名次空缺

# 剛學的順便用一用
select sid,sum(score) as total,
row_number() over(order by sum(score) desc) as 'rank'
from sc
group by sid
set @ranks = 0;
select sid,t.total,@ranks:=@ranks+1 from(
select sid,sum(score) as total from sc
group by sc.sid
order by total desc)t

17 統計各科成績各分數段人數:課程編號,課程名稱,[100-85],[85-70],[70-60],[60-0] 及所占百分比

select course.CId,course.Cname,t1.*
from course LEFT JOIN (
select sc.CId,CONCAT(sum(case when sc.score>=85 and sc.score<=100 then 1 else 0 end )/count(*)*100,'%') as '[85-100]',
CONCAT(sum(case when sc.score>=70 and sc.score<85 then 1 else 0 end )/count(*)*100,'%') as '[70-85)',
CONCAT(sum(case when sc.score>=60 and sc.score<70 then 1 else 0 end )/count(*)*100,'%') as '[60-70)',
CONCAT(sum(case when sc.score>=0 and sc.score<60 then 1 else 0 end )/count(*)*100,'%') as '[0-60)'
from sc
GROUP BY sc.CId) as t1 on course.CId=t1.CId

18 查詢各科成績前三名的記錄

# 這里是看來的,就是成績比自己大的有哪些,小於3就是前三的0 ,1 ,2
select cid,sid,score from sc
where (select count(*) from sc a where a.cid = sc.cid
and a.score > sc.score) < 3
order by cid, score desc

19 查詢每門課程被選修的學生數

select count(sc.cid) from sc
group by sc.cid

20 查詢出只選修兩門課程的學生學號和姓名

select s.sid,s.sname from student s
join sc on s.sid = sc.sid
group by sc.sid
having count(sc.cid) = 2

21 查詢男生、女生人數

select ssex,count(sid) from student
group by ssex

22 查詢名字中含有「風」字的學生信息

select s.* from student s
where s.sname like '%風%'

23 查詢同名同性學生名單,並統計同名人數

select sname,count(sname) from student 
group by sname
having count(sname) >=  2

24 查詢 1990 年出生的學生名單

select s.sid, s.sname from student s
where year(s.sage) = 1990

25 查詢每門課程的平均成績,結果按平均成績降序排列,平均成績相同時,按課程編號升序排列

select sc.cid,c.cname,avg(sc.score)平均成績 from sc
join course c on sc.cid = c.cid
group by sc.cid
order by avg(sc.score) desc, sc.cid

26 查詢平均成績大於等於 85 的所有學生的學號、姓名和平均成績

select s.sid,s.sname,avg(sc.score) 平均分 from student s
join sc on s.sid = sc.sid
group by sc.sid
having avg(sc.score) > 85

27 查詢課程名稱為「數學」,且分數低於 60 的學生姓名和分數

# 兩次做的竟然寫出不一樣的東西~~
select s.sname,sc.score from student s
join sc on s.sid = sc.sid
join course c on sc.cid = c.cid
where c.cname = '數學'
and sc.score < 60
select s.sname,sc.score
from student s
join sc on s.sid = sc.sid
where sc.cid = (
select c.cid from course c
where cname = '數學')
and sc.score < 60

28 查詢所有學生的課程及分數情況(存在學生沒成績,沒選課的情況)

select * from student s
left join sc on s.sid = sc.sid

29 查詢任何一門課程成績在 70 分以上的姓名、課程名稱和分數

select s.sname,c.cname,sc.score from student s
join sc on s.sid = sc.sid
join course c on sc.cid = c.cid
where sc.score > 70

30 查詢存在不及格的課程

select sc.cid,c.cname from sc
join course c on sc.cid = c.cid
where sc.score < 60
group by sc.cid

31 查詢課程編號為 01 且課程成績在 80 分及以上的學生的學號和姓名

select s.sid,s.sname from student s
join sc on s.sid = sc.sid
where sc.cid = 01
and sc.score >= 80

32 求每門課程的學生人數

select sc.cid, count(sc.sid) from sc
group by sc.cid

33 成績不重復,查詢選修「張三」老師所授課程的學生中,成績最高的學生信息及其成績

select s.*,sc.score,sc.cid from teacher t
join course c on t.tid = c.tid
join sc on c.cid =sc.cid
join student s on sc.sid = s.sid
where t.tname = '張三'
having max(sc.score)
select s.* ,max(sc.score),sc.cid from student s
join sc on s.sid = sc.sid
join course c on sc.cid = c.cid
join teacher t on c.tid = t.tid
where t.tname = '張三'

34 成績有重復的情況下,查詢選修「張三」老師所授課程的學生中,成績最高的學生信息及其成績

# 最高分是90分 ,新增一個90分,然后找出最高分為90分的學生信息和成績

35 查詢不同課程成績相同的學生的學生編號、課程編號、學生成績

select a.cid,a.sid,a.score from sc a
join sc b on a.sid = b.sid
where a.score = b.score
and a.cid != b.cid
group by cid

36 查詢每門功成績最好的前兩名

# 感覺和前面那題一樣,比外面大的 個數,小於2
select sid,cid,score from sc
where (select count(*) from sc a where sc.cid = a.cid and a.score > sc.score ) < 2
order by cid

37 統計每門課程的學生選修人數(超過 5 人的課程才統計)

select cid,count(sc.sid) from sc 
group by cid
having count(sc.cid) > 5

38 檢索至少選修兩門課程的學生學號

select sid,count(cid) from sc
group by sid
having count(cid) >=2

39 查詢選修了全部課程的學生信息

select sid,count(cid) from sc
group by sid
having count(cid) = (select count(*) from course)

40 查詢各學生的年齡,只按年份來算

select sid,sname,timestampdiff(year, sage, now())as 年齡 from student;
select sid,sname,timestampdiff(year, sage, curdate())as 年齡 from student;

41 按照出生日期來算,當前月日 < 出生年月的月日則,年齡減一

# 好像和上面的一樣

42 查詢本周過生日的學生

# yearweek(sage) = xxxxaa      (xxxx是年,aa是第幾周)
select * from student
where week(sage) = week(curdate())

43 查詢下周過生日的學生

select * from student
where week(sage) = week(curdate()) +1

44 查詢本月過生日的學生

select * from student
where month(sage) = month(curdate())

45.查詢下月過生日的學生

select * from student
where month(sage) = month(curdate())+1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM