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;