SQL練習題 51題 一刷


 

Student表:

select * from student;

 

課程表Course:

select * from course;

 

教師表teacher:

select * from teacher;

 

 

成績表Score:

select * from sc;

 

 

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

select c.*, a.score from sc a, sc b, student c where a.sid=b.sid and c.sid=a.sid and a.cid=1 and b.cid=2 and a.score>b.score;  #笛卡爾積形式的連接,不能加上a.cid=b.cid

 

 

 

 2、查詢同時選" 01 "課程和" 02 "課程的學生

select a.sid from sc a, sc b where a.sid=b.sid and a.cid=1 and b.cid=2;

 

 

 

3、查詢選修了" 01 "課程但可能沒有選修" 02 "課程的學生情況(不存在時顯示為 null )

 方法一:

select *   from (select * from sc where cid=1) a left join (select * from sc where cid=2) b on a.sid=b.sid;

 

 

方法二:

select *
from student a left join SC b on a.SID = b.SID and b.CID = '01'
left join SC c on a.SID = c.SID and c.CID = '02'
where  b.score is not null; 

運行結果:沒有where子句時,中間表的連接結果如下圖,題目要求選修了1號課程,可能沒有選修2號課程,所以根據下圖的結果,可以得知,只要把選修了1號課程的同學查詢出來即可,即where子句中的條件為: b.score is not null 

 

 

 

方法三:  這種方法和方法二相同,只是where 子句有所不同,如果想使用方法三,where子句的條件需要修改為b.score>= isnull(c.score),

原因是b.score>isnull(c.score),

假定c.score是null,isnull(c.score)返回的結果為1,那么當b.score=1時,此時b.score>isnull(c.score)不成立,那么這一條記錄就會被過濾掉

select a.* , b.score  b_score ,c.score  c_score from Student a left join SC b on a.SID = b.SID and b.CID = '01'

left join SC c on a.SID = c.SID and c.CID = '02'

where  b.score > = isnull(c.score);   #,注意,是>=, 這一句,目的是為了篩選出b表中不為null的成績,因為isnull(c.score)返回結果只有0和1兩種情況

 

思路解析:

select a.* , b.score  b_score ,c.score  c_score from Student a left join SC b on a.SID = b.SID and b.CID = '01'

left join SC c on a.SID = c.SID and c.CID = '02';

 

 

isnull( )使用說明:

  

 

 

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

 思路:選修2課程的id號課程中,剔除選修了1課程的id 號

select  distinct sid from sc where cid=2 and sid not in (select sid from sc where cid=1 );

 

 

 

 

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

select student.sid, student.sname, count(sc.cid) as "選課總數", sum(sc.score) as "總成績" from student left join  sc  on student.sid=sc.sid group by student.sid  ;

 

 

8、查詢「李」姓老師的數量

#(例子:查詢以s開頭的老師數量)

select count(*) from teacher where tname like 's%';

 

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

(例子:查詢學過 jane 老師授課的學生信息)

select student.*
from student, sc, course, teacher where student.sid=sc.sid and sc.cid=course.cid and  course.tid=teacher.tid and teacher.tname='jane';

 

 

中間表:

select *
from student, sc, course, teacher where student.sid=sc.sid and sc.cid=course.cid and  course.tid=teacher.tid ;

 

 

 

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

 

select  student.*
from sc , student where student.sid=sc.sid group by sc.sid having count(sc.cid)<(select count(*) from course);  # 查詢課程表course中有多少門課

 

 

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

ps:把1號同學排除

 

select  distinct student.*

from student, sc where student.sid=sc.sid and  sc.sid!=1 and  sc.cid in ( select distinct cid from sc where sid=1);

 

 

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

 正確代碼:

 此時SC表如圖:可以看到,將sid分組的情況下,除6號同學外,每個同學的成績記錄都是按照cid增序的順序插入的;只有6號同學的課程插入順序是1,3,2

 

 

 上面這張表不太容易看,對sid按增序排序后,如下圖,查看每個同學cid插入的順序如何,注意:只對sid排序,對cid排序后就不能看出來每個同學cid插入的順序如何了。

排序后,可以更清楚的看到只有6號同學的課程插入順序是亂的,不是按照cid增序插入的。

 

 

 

 

 

完全正確的代碼:

PS:不僅使用了group_concat( )函數,還對group_concat( )函數中的參數進行了排序。

select student.*
from 
(select sid, group_concat(cid order by cid) as  tt from sc  where sid=1  group by sid  order by cid ) a   #1號同學選修的課程
        #這里對cid進行了排序,因為group_concat()函數連接cid的值時,默認是按照該值在SC表中的插入順序進行連接的
left join 

( select sid, group_concat(cid order by cid) as rr  from sc  where sid!=1  group by sid order by cid ) b    on a.tt=b.rr  
# #除1號同學外,其他同學選修的課程,將兩張表進行連接,按照選修課程相同為條件進行連接

join student on b.sid=student.sid;

運行結果:

 

 

 

下面代碼也有漏洞:group _concat( cid)中不對cid排序,則返回結果如下:

select student.*
from 
(select sid, group_concat(cid ) as  tt from sc  where sid=1  group by sid  order by cid ) a 
       
left join 

( select sid, group_concat(cid ) as rr  from sc  where sid!=1  group by sid order by cid ) b    on a.tt=b.rr  

join student on b.sid=student.sid;

運行結果:只查詢出了4號同學

 

 

必須要排序的原因: 可以看到,1,4,6號同學選的課程都一樣,只是6號同學課程插入時是亂序的,結果造成下面這種情況,連接的結果也是按插入順序連接的,這樣,系統認為1號同學和6號同學的課程是不一樣的,所以group_concat( cid )中要對cid排序,即使用group_concat( cid order by cid)

select sid, group_concat(cid) as '選修課程'  from sc  group by sid;

運行結果:

 

 

 

總結:
  按同學分組后,如果每個同學的課程插入記錄是順序增加或順序降低的,則使用group_concat( )函數時不對參數進行排序,沒有問題。

  但如果每個同學的課程插入記錄是亂序的,則使用group_concat( )函數時必須對參數進行排序。

 

 

錯誤代碼: 下面的代碼看似正確,其實有漏洞,很有迷惑性

 

分析: 假定一共有4門課,課程號cid=1,2,3,4;    SC表如下,其中1同學、4同學、6同學都選修了1,2,3這三門課,不存在選修了全部課程的同學,這種情況下,使用下面代碼解決這道題目沒有問題,但是

 

 

 假定表的情況按上述情況,運行下面代碼,返回的結果看似是正確的:

select  student.*
from sc ,student where  student.sid=sc.sid  and sc.cid in   ( select cid from sc where sid=1)  and    student.sid!=1
group by sc.sid having count(*) in (select count(*) from sc where sid=1);

運行結果:

 

 

 

舉一個例子揭示上述代碼的漏洞:

在上面的那張表中,插入了一條記錄,結果就是6號同學選修了全部課程,那么此時,只有4號同學和1號同學選修的課程完全相同

 

 同樣運行上面代碼,查看運行結果:

 

 

select  student.*
from sc ,student where  student.sid=sc.sid  and sc.cid in   ( select cid from sc where sid=1)  and    student.sid!=1
group by sc.sid having count(*) in (select count(*) from sc where sid=1);

運行結果: 仍然把6號同學給選了出來,此時,正確的結果應當只有第一條

 

 

 

 

 

 

 

 

 

 

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

(例子:smith老師)

思路:先把學過smith老師課程的學號選出來,然后從student表中剔除這些學號

 

select student.*
from student where sid not in ( select sid from sc ,course, teacher where sc.cid=course.cid and course.tid=teacher.tid and  teacher.tname='smith');

 

 

 

 

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

 

A:查詢出兩門以上不及格的學號

select sid from sc where score<60
group by sid having  count(*)>=2;

 

A:完整結果

 個人理解:我理解的平均成績某個同學所有選修課程的平均成績,而不是不及格課程的平均成績。

例如,2號同學選了3門課,有2門不及格,平均成績是指3門的平均成績,而不是2門的。

 

select student.sid, student.sname, avg(sc.score) from (student join sc on student.sid=sc.sid )  join ( select sc.sid as esid from sc where sc.score<60
group by sc.sid having  count(*)>=2) a on student.sid=a.esid group by student.sid order by student.sid;

運行結果:

 

 

 

 

 

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

 

select student.*
from sc,student where cid=1 and score<60 and sc.sid=student.sid order by score desc;

 

 

 

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

select sc.*, a.avgscore from sc left join (select sid, avg(score) as avgscore from sc group by sid) a on sc.sid=a.sid order by a.avgscore desc;

 

 

 

 

 

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

select cid, max(score), min(score), avg(score) from sc group by cid;

 

 

 

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

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

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

select sc.cid, course.cname,count(sc.sid) as '選修人數', max(sc.score), min(score), avg(score), (sum(case when score>=60 then 1 else 0 end)/count(sc.sid)) as '及格率', (sum(case when score>=70 and score<80 then 1 else 0 end) /count(sc.sid)) as '中等率', (sum(case when score>=80 and score<90 then 1 else 0 end)/count(sc.sid)) as '優良率', (sum(case when score>=90 then 1 else 0 end)/count(sc.sid)) as '優秀率'
 
from sc, course where sc.cid=course.cid group by sc.cid order by count(sc.sid) desc, cid ; #按選修人數降序排列,如果人數相同,按課程號cid升序排列

 

 

 

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

 思路:這里不能使用a.score<=b.score

select  a.sid ,a.cid, a.score, count(a.score<b.score)+1  as rank from sc a  left join sc b  on a.cid=b.cid  and a.score<b.score group by a.cid, a.sid order by a.cid, a.score desc;

 

 

 

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

 思路:看某個分數在所有分數中,小於等於的有幾個

select  a.sid ,a.cid, a.score, count( distinct b.score)+1 as rank from sc a left join   sc b  on a.cid=b.cid  and a.score<b.score group by a.cid, a.sid order by a.cid, a.score desc;

或者   如果是a.score<=b.score,則count( distinct b.score) 即可,不用加1

select  a.sid ,a.cid, a.score, count( distinct b.score) as rank from sc a left join   sc b  on a.cid=b.cid  and a.score<=b.score group by a.cid, a.sid order by a.cid, a.score desc;

 

 

 

 

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

 

select a.* ,count(a.cj<b.cj)+1 as rank from (select sid , sum(score)  as cj  from sc  group by sid) a left join ( select sid, sum(score) as cj from sc group by sid) b on a.cj<b.cj group by a.sid order by a.cj desc ;

 

 

 

 

 

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

 

select a.* ,count(distinct b.cj)+1 as rank from (select sid , sum(score)  as cj  from sc  group by sid) a left join ( select sid, sum(score) as cj from sc group by sid) b on a.cj<b.cj group by a.sid order by a.cj desc ;

 

 

 

 

 

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

 

select sc.cid,cname,count(sid) as '總人數', concat(round(sum(case when score>=0 and score<60 then 1 else 0 end) /count(sid)*100,2),'%') as '0-60', concat(round(sum(case when score>=60 and score<70 then 1 else 0 end)/count(sid)*100,2),"%")  as '60-70', concat(round(sum(case when score>=70 and score<85 then 1 else 0 end)/count(sid)*100,2),"%") as '70-85', concat(round(sum(case when score<=100 and score>=85 then 1 else 0 end )/count(*)*100,2),'%') as '85-100'


from sc join course on sc.cid=course.cid group by cid;

 

 

 

 

 

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

 思路:先將各科成績進行排序(這里應該是不保留名次空缺),然后從成績表SC中選出排名<=3的記錄

select * from ( select a.*, count(distinct b.score) +1 as rank from sc a left join sc b on a.cid=b.cid and a.score<b.score group by a.cid, a.sid order by a.cid, a.score desc) c where c.rank<=3 ;

 

 

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

select cid, count(*) as '選修人數' 
from sc group by cid;

 

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

select sc.sid, student.sname from student, sc where student.sid=sc.sid group by sc.sid having count(sc.cid)=2;

 

27、查詢男生、女生人數

select ssex as '性別' , count(*) as '人數'
from student group by ssex;

 

 

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

select * from student  where sname like '%m%'; #這個是查詢姓名含有m的學生信息,m在開頭或者中間位置都可以 select * from student where sname like 'm%';  #這個是查詢姓名以m開頭的學生信息

 

 

29、查詢同名同姓學生名單,並統計同名人數

 

select sname , count(*) as '人數'
from student group by sname;

 

 

 

30、查詢 1990 年出生的學生名單

 

select * from student where sage like "1990%" ;

 

 

 

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

select cid, avg(score) as '平均成績'
from sc group by cid order by avg(score) desc, cid;

 

 

 

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

 

select student.sid, student.sname, a.pj from student join (select sid, avg(score) as 'pj'
from sc group by sid having avg(score)>=85) a on student.sid=a.sid ;

 

 

 

 

 

 

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

 

select student.sname, score from student, sc, course where student.sid=sc.sid and sc.cid=course.cid and score<60 and cname='math';

 

 

 

 

 

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

select student.sid,student.sname, sc.cid,sc.score from student left join sc on student.sid=sc.sid order by student.sid;

 

1 mark 1 80
1 mark 3 95
1 mark 2 90
2 james 2 39
2 james 3 39
2 james 4 94
3 michael 1 93
3 michael 3 87
4 jack 2 74
4 jack 1 89
4 jack 3 83
5 mei 1 76
5 mei 2 47
6 lily 4 44
6 lily 1 41
6 lily 3 83
7 nana 3 83
7 nana 2 89
8 mifei  NULL NULL 
9 cry  NULL NULL 

 

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

select sname, cname ,score from (sc join student on sc.sid=student.sid) join course on sc.cid=course.cid where  score>70
order by sc.sid;

 

 

 

 

36、查詢不及格的課程

select course.cname, sc.score from sc join course on sc.cid=course.cid where sc.score<60;

 

 

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

 

select student.sid, student.sname from student ,sc where student.sid=sc.sid  and sc.cid=1 and sc.score>80
order by cid ;

 

 

 

 

 

38、求每門課程的學生人數

select cid, count(*) as '該課程的選修人數'
from sc group by cid;

 

 

 

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

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

PS:這兩道題,使用下面同樣的代碼都能運行出正確結果

 

 

select student.*, a.score
from sc a left join sc b on a.cid=b.cid and a.score<b.score   #對每門課程下的學生成績排名

join course on a.cid=course.cid   
join teacher on course.tid=teacher.tid and tname='張三'  #這一行和上一行,是為了篩選張三老師教的課
join student on a.sid=student.sid  # 獲取學生信息

group by a.cid, a.sid  
having count( a.score< b.score)=0   #篩選名次rank=1, count(a.score<b.score)+1=1,兩端減去1,簡化為count(a.score<b.score)=0

#上面這一行having 子句,這種格式也可以:having count( distinct b.score)=0 ,使用distinct
;

 

 

 

 

 

 

 

 

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

 

select sc.cid , sc.sid, sc.score
from sc join  (select cid, score from sc  group by cid, score having count(sid)>=2) a 
        on sc.cid=a.cid and sc.score=a.score
order by cid ;

 

select    sc.sid, sc.cid , sc.score
from sc join  (select sid, score from sc  group by sid, score having count(cid)>=2) a 
        on sc.sid=a.sid and sc.score=a.score
order by sid;

 

 

 

 

 

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

思路:先對每門課程下的成績排序,然后篩選排名<=2的

select a.cid, a.sid, sname, a.score,  count(distinct b.score)+1 as 'rank'
from ( sc a left join sc b on a.cid=b.cid and a.score<b.score) join student on a.sid=student.sid group by a.cid, a.sid having rank<=2
order by cid ;

 

 

 

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

select sc.cid,cname,count(sid) as '選修人數'
from sc join course on sc.cid=course.cid group by sc.cid having count(sid)>4;

 

 

 

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

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

 

 

 

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

select student.*
from sc join student on sc.sid=student.sid group by sid having count(*) in ( select count(*)  from course);

 

 

計算年齡,只按年份來算和按月日來算的區別

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

select student.sid, student.sname,student.ssex, year(now())-year(student.sage)  as 'age'
from student;

 

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

 

select student.sid, student.sname,student.ssex, sage, timestampdiff(year,sage,now()) as '按月日計算',  # 出生月日< 當前日期的月日時,年齡會減一 ,該題目功能是通過這一句實現的,下一句只是為了對比說明兩者之間的差別 year(now())-year(sage) as '按年份計算'  
from student; 

 

 

 

 

48、查詢本周過生日的學生

 

select * 
from student 
where week(concat_ws('-',year(now()),date_format(sborn,'%m-%d')))=week(now());

 

 

 

 

49、查詢下周過生日的學生

 

select * 
from student 
where week(concat_ws('-',year(now()),date_format(sborn,'%m-%d')))=week(now())+1;

 

 

 

50、查詢本月過生日的學生

select *
from student where month(student.sage)=month(now());

 

 

51、查詢下月過生日的學生

select *
from student where month(student.sage)=month(now())+1;

 


免責聲明!

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



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