建表與資料準備
建庫和建表的操作請看上篇的內容,在此不再贅述。
use day5; # 切換day5為當前資料庫show tables;Tables_in_day5 coursescorestudentteacher
練習題
第六題:
查詢各科成績最高和最低的分:以如下形式顯示:課程ID,最高分,最低分:這題很簡單,不需要連表,只要課程id、最高分和最低分,用分組函式就能搞定:
select course_id 課程id,max(num) 最高分,min(num) 最低分 from score group by course_id;
第七題:查詢至少有一門課與學號1所學課程相同的學生學號和姓名:
1.從socre表中查出學號1學的全部課程id:
select course_id from score where student_id=1;
2.再從score表中找含有學號1課程的記錄,記得要去重而且要去掉學號1:
select distinct student_id from score where student_id!=1 and course_id in( select course_id from score where student_id=1);
3.最後與student表拼接,顯示學號和姓名,注意要right join(因為右表記錄不能遺漏的),另外可以加上order by學號更加美觀:
select sid 學號,sname 姓名 from student as a right join (select distinct student_id from score where student_id!=1 and course_id in( select course_id from score where student_id=1)) as b on a.sid=b.student_id order by 學號;
第八題:查詢語文成績比數學成績好的學生學號及名字:
這道題這裡講一個新東西,用變數儲存查詢結果及呼叫變數儲存的查詢結果。請注意變數的用法——@變數名字:1.首先查詢course表中語文的課程id和數學課程的id:
select @course1:=cid # 查詢語文課的id,儲存到變數course1中 from course where cname='語文';select @course2:=cid # 查詢數學課的id,儲存到變數course2中 from course where cname='數學';
2.做一個學號、語文課成績、數學課成績的連表:
select a.學號,a.課程1,b.課程2 from( select student_id 學號,num 課程1 from score where course_id=@course1) a inner join( select student_id 學號,num 課程2 from score where course_id=@course2) b on a.學號=b.學號 where 課程1>課程2;
3.最後與student表拼接,顯示學號和姓名,注意要right join(因為右表記錄不能遺漏的),另外可以加上order by學號更加美觀:
select sid 學號,sname 姓名 from student right join( select a.學號,a.課程1,b.課程2 from( select student_id 學號,num 課程1 from score where course_id=@course1) a inner join( select student_id 學號,num 課程2 from score where course_id=@course2) b on a.學號=b.學號 where 課程1>課程2) c on student.sid=c.學號 order by 學號;
注意:這一題運用了一個新技巧,臨時變數儲存臨時查詢結果。為了提高程式碼的複用率,在經常變更查詢內容但不變更查詢條件的情況下,用臨時變數單獨儲存查詢內容會很方便。另外就是如果發現某些查詢的結果需要反覆用到,那麼可以先將該結果儲存到臨時變數中,這樣可以減少查表次數從而提高查詢效率。
第九題:查平均成績大於60分的學生學號、姓名、平均成績,結果按成績從高到低排序:
這一題寫SQL程式碼難度不大,難的是要找出題中隱含條件。在這道題中要找出平均成績大於60分的學生,但在資料庫存在有些學生部分課程缺考的情況,缺考的課程應該按0計算!所以不能直接用avg(num)>60來作為having條件。1.首先查course表得出總共有幾門課程:
select @total:=count(*)*60 # 計算平均成績大於60考分的總數 from course;
2.再從score表查總成績大於@total的學生,獲取學號和平均成績:
select student_id 學號,avg(num) 平均成績 from score group by student_id having sum(num)>@total order by 平均成績 desc;
3.最後連線student表,顯示學生學號、姓名、平均成績:
select 學號,sname 姓名,平均成績 from student a inner join( select student_id 學號,avg(num) 平均成績 from score group by student_id having sum(num)>@total order by 平均成績 desc) b on a.sid=b.學號;
第十題:查詢所有學生的學號、姓名、總成績、課程數,按總成績從高到低排序:
這一題寫SQL程式碼難度不大,但還是有很多人會做錯。請注意題目要求是查詢所有學生的資訊,連表的時候必須使用student左連線右查詢子表,這樣才能查到所有學生的資訊!請實際執行一下程式碼,就會發現有一個學生是沒成績的。假如用的是inner join那麼答題結果就不會包含沒成績的學生。
select student.sid 學號,student.sname 姓名,b.總成績,b.課程數 from student left join (select student_id 學號,count(num) 課程數,sum(num) 總成績 from score group by student_id) as b on student.sid=b.學號 order by 總成績 desc;
第十一題:查詢沒上過“江成”老師課的學生學號和姓名;
這一題有難度,要避開兩個坑:一是要想到一名老師可能教多門課;二是要會用逆向思維,從score表中找出所有上過“江成”老師課的學生,然後再從student表中排除那些學生,剩下的就是沒上過“江成”老師課的學生。1.從teacher表中找出“江成”老師的id,再去course表中找出“江成”老師教的全部課程:
select cid from course where teacher_id=( select tid from teacher where tname='江成');
2.從score表中找出所有學過“江成”老師’的學生id,另外要記得用distinct去重:
select distinct student_id from score where course_id in ( select cid from course where teacher_id=( select tid from teacher where tname='江成'));
3.從student表中找出所有不在第二步表中的學生:
select sid 學號,sname 姓名 from student where sid not in( select distinct student_id from score where course_id in ( select cid from course where teacher_id=( select tid from teacher where tname='江成')));
第十二題:查詢學過“江成“老師所有課程的學生學號和姓名:
這一題比上一題還要難,解題思路是首先要找出這位老師教的所有課程(可能不止一門課),其次計算這位老師教了幾門課;然後找出學過這位老師課程的學生另外排除掉課程數量不足的學生;最後再拼接學生表列出學號和姓名。1.找出“江成”老師教的全部課程:
select cid from course where teacher_id=( select tid from teacher where tname='江成');
2.算出“江成”老師教幾門課:
select @total:=count(*) from course where teacher_id=( select tid from teacher where tname='江成');
3.找出學過“江成”老師課的學生,只保留成績數量等於老師教的課程數的學生:
select student_id from score c inner join( select cid from course a inner join( select tid from teacher where tname='江成') b on a.teacher_id=b.tid) d on c.course_id=d.cid group by student_id having count(student_id)=@total;
4.再將第三步的表與student表拼接,最終顯示學過“江成“老師所有課程的學生學號和姓名:
select sid 學號,sname 姓名 from student e inner join( select student_id from score c inner join( select cid from course a inner join( select tid from teacher where tname='江成') b on a.teacher_id=b.tid) d on c.course_id=d.cid group by student_id having count(student_id)=@total) f on e.sid=f.student_id order by 學號;