題記:從知乎上看到的一篇文章,恰好最近工做中發現遇到的題目與這個幾乎同樣,可能就是從這裏來的吧。^_^sql
裏面的答案沒有細看,SQL求解重在思路,不少時候同一種結果可能有多種寫法,好比題中的各科成績取前三名,我是在看到這篇文章想到的另外一種寫法,不過題中的寫法也能夠作爲參考學習。以此記錄。函數
如下轉自:https://zhuanlan.zhihu.com/p/72223558學習
這篇文寫了挺久了,有一位細心的小夥伴滑稽發現了一個錯誤,很感謝有人認真的在看,我從新修改了一下! 測試
好久以前我寫過一篇學習sql的基本操做,可是本身好像在sql上面有點停滯了。最近有和一位朋友聊過如何學習sql,朋友給個人回覆是多寫代碼。我深覺得然因而就找到了這個經典的50題。spa
雖然這個經典50題網上有不少人分享過,可是,只有本身實際操做過之後才能真正的理解其中的坑,也纔可以加深對知識的理解吧。我但願本身可以作一套很詳細的解析。.net
解析包含:1解題思路,2相關知識,3 實際語句實現;3d
申明:我只是一個初學者,還有不少不懂的地方,因此若是您發現了錯誤,但願能在下邊提出來,萬分感謝!code
若是你以爲我很走心,也歡迎點贊!orm
首先建表,主要有四個表,學生表(Student),課程表(Course),教師表(Teacher),以及成績表(SC)blog
在分別介紹一下每一個表的字段 學生表(Student )有四個字段 sid--學生id,sname--學生姓名,sage--學生年齡,ssex--學生性別
課程表(Course)有三個字段,cid--課程id,cname--課程名,tid--教師id
教師表(Teacher)有兩個字段,tid--教師id,tname--教師姓名
成績表(SC)有三個字段,sid--學生id,cid--課程id,score--成績
咱們用腦圖的方式繪製出來,以下所示
學生表結構
課程表結構
教師表結構
成績表結構
各個表之間的關係以下,Student和SC表經過學生id(sid)來鏈接,Course和Teacher表經過教師id(tid)鏈接,SC和Course表經過課程id(cid)來鏈接。
create table Student(sid varchar(10),sname varchar(10),sage datetime,ssex nvarchar(10)); insert into Student values('01' , '趙雷' , '1990-01-01' , '男'); insert into Student values('02' , '錢電' , '1990-12-21' , '男'); insert into Student values('03' , '孫風' , '1990-05-20' , '男'); insert into Student values('04' , '李雲' , '1990-08-06' , '男'); insert into Student values('05' , '周梅' , '1991-12-01' , '女'); insert into Student values('06' , '吳蘭' , '1992-03-01' , '女'); insert into Student values('07' , '鄭竹' , '1989-07-01' , '女'); insert into Student values('08' , '王菊' , '1990-01-20' , '女'); create table Course(cid varchar(10),cname varchar(10),tid varchar(10)); insert into Course values('01' , '語文' , '02'); insert into Course values('02' , '數學' , '01'); insert into Course values('03' , '英語' , '03'); create table Teacher(tid varchar(10),tname varchar(10)); insert into Teacher values('01' , '張三'); insert into Teacher values('02' , '李四'); insert into Teacher values('03' , '王五'); 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"課程成績高的學生的信息及課程分數
解題思路:要查詢的是兩個課程的成績,並且還要顯示學生的信息。因此須要用到兩張表,SC,Student這兩張表。
問題拆分:(1) 怎麼查找兩個課程的成績呢? (2) 如何把課程表和學員信息錶鏈接起來呢?
那麼用到哪些知識呢?
(1) 子查詢 (2) join
語句實現:先找到兩門課的成績
-- 課程1的成績 SELECT sid ,score AS class1 FROM sc WHERE sc.cid = '01'; -- 課程2的成績 SELECT sid,score AS class2 FROM sc WHERE sc.cid = '02';
class1 查詢結果
class2 查詢結果
兩個子查詢結束了之後,下一步就是使用join把這兩個查詢的結果鏈接起來
SELECT * FROM Student RIGHT JOIN (SELECT t1.sid,class1,class2 FROM -- 這個是要查詢兩個表的成績,即課程1大於課程2 (SELECT sid ,score AS class1 FROM sc WHERE sc.cid = '01') AS t1, (SELECT sid,score AS class2 FROM sc WHERE sc.cid = '02') AS t2 WHERE t1.sid = t2.sid AND t1.class1 > t2.class2) r -- 這裏是固定的,就是子查詢的一個別名的設置 -- 這一步就是把兩個表按照sid聯結起來 ON Student.sid = r.sid;
最終查詢結果
好的,,第一題就解決了
第二題:1.1 查詢存在" 01 "課程但可能不存在" 02 "課程的狀況(不存在時顯示爲 null )
思路:首先要查詢全部的學生的選課狀況,而後找到選擇課程1和選擇課程2的學生
解決方法: 使用join
選擇兩個分別選擇課程1和課程2的學員表,而後把這兩個表join起來
SELECT * FROM(SELECT * FROM sc WHERE sc.cid = '01' ) t1 LEFT JOIN (SELECT * FROM sc WHERE sc.cid = '02') t2 ON t1.sid = t2.sid ;
輸出結果
1.2 查詢同時存在01和02課程的狀況
思路:要求同時選擇了01和02課程的狀況,則須要使用where連接起來,這一題和上一題相比就是多了一個去除選了01可是沒有選擇02課程的這一部分
知識點:子查詢,where語句
SELECT * FROM (SELECT * FROM sc WHERE sc.cid = '01') AS t1, (SELECT * FROM sc WHERE sc.cid = '02') AS t2 WHERE t1.sid = t2.sid;
執行結果
1.3 查詢選擇了02課程但沒有01課程的狀況
思路,要求首先獲得選擇了02課程的學員,而後剔除掉選擇01課程的學員
知識點:子查詢,NOT IN
SELECT * FROM sc WHERE sc.sid NOT IN (SELECT sid FROM sc WHERE sc.cid = '01') AND sc.cid = '02';
寫好了這個語句之後我以爲本身寫的不夠清楚,所以我使用了別名
看一下結果:
SELECT * FROM sc WHERE sc.sid NOT IN (SELECT sid FROM sc WHERE sc.cid = '01') AND sc.cid = '02';
執行結果
小結:上面幾個題基本能夠說是同一類型,要注意子查詢的使用,以及join和where的區別
2.查詢平均成績大於等於 60 分的同窗的學生編號和學生姓名和平均成績
思路:看到這個題的時候第一想法是要使用group by,和having,又由於成績表(sc)沒有學生姓名,因此還要使用join,固然avg確定是須要的
考察知識:group by,join
SELECT s.sid,sname,AVG(sc.score) FROM student AS s INNER JOIN sc ON s.sid = sc.sid GROUP BY sc.sid HAVING AVG(sc.score) >= 60;
執行結果
還有一種解法,使用子查詢
SELECT r.*, s.sname FROM (SELECT sid,AVG(score) FROM sc GROUP BY sid HAVING AVG(score) > 60) r LEFT JOIN student AS s ON s.sid = r.sid;
3.查詢在 SC 表存在成績的學生信息
思路:這題比較簡單,就是兩張表經過id鏈接,而後求單獨值
知識點:Distinct
SELECT DISTINCT student.* FROM sc,student WHERE student.sid = sc.sid ;
執行結果
4.查詢全部同窗的學生編號、學生姓名、選課總數、全部課程的成績總和
解題思路:首先用到兩張表格,而後要求選課總數,和成績總和,那麼就須要用到groupby 和sum以及count
知識點:gruop by, sum,join,count
SELECT s.sid,s.sname,COUNT(sc.cid),SUM(score) FROM student AS s INNER JOIN sc ON s.sid = sc.sid GROUP BY sc.sid;
執行結果
5.查詢「李」姓老師的數量
解題思路:這題考的是通配符的查詢,好比使用like和%
知識點:count,like,%
SELECT COUNT(*) FROM teacher WHERE tname LIKE ('李%');
執行結果
6.查詢學過「張三」老師授課的同窗的信息
解題思路:要查找張三老師的授課科目,而後經過科目和score錶鏈接,而後再和學生錶鏈接
知識點:就是多重鏈接 inner join
SELECT s.* FROM student AS s INNER JOIN sc ON s.sid = sc.sid INNER JOIN course AS c ON sc.cid = c.cid INNER JOIN teacher AS t ON t.tid = c.tid WHERE t.tname = '張三';
執行結果
7.查詢沒有學全全部課程的同窗的信息
解題思路:首先利用子查詢查詢course表查詢獲得共有幾門課,按照groupby的方式求課程數加上having小於查詢出來的課程的全部學員信息就好
知識點:子查詢,groupby,having,join
SELECT s.*,COUNT(cid) FROM sc RIGHT JOIN student AS s ON sc.sid = s.sid GROUP BY sc.sid HAVING COUNT(cid) < (SELECT COUNT(DISTINCT cid) FROM course);
執行結果
網友的有一種比較好的作法,是使用not in
SELECT s.* FROM student AS s WHERE s.sid NOT IN (SELECT sc.sid FROM sc GROUP BY sc.sid HAVING COUNT(cid) >= 3);-- 這一句也可使用子查詢
執行結果
8.查詢至少有一門課與學號爲" 01 "的同窗所學相同的同窗的信息
解題思路:首先要查詢出01同窗所學的課程,而後使用cid in 01同窗的課程,並排除sid=01的同窗
SELECT s.* FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE sc.cid IN (SELECT cid FROM sc WHERE sid = '01') AND sc.sid != '01' GROUP BY sc.sid;
執行結果
我這裏使用了groupby語句來求取單個學員id,也可使用distinct關鍵字來作區分
SELECT DISTINCT s.* FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE sc.cid IN (SELECT cid FROM sc WHERE sid = '01') AND sc.sid != '01';
執行結果
這裏就有一個知識點就是group by有去除重複值的功能,這個其實不難理解,由於group by就是按照單個組分類,能夠理解爲按照同一類進行切分
9.查詢和" 01 "號的同窗學習的課程徹底相同的其餘同窗的信息
解題思路:首先感受真題很難,想法是在student表的sid在sc的id中,而這個id又和cid相關聯,而後再查詢結束時,還要排除id=01的狀況。反正很複雜。。。
知識點:n重子查詢,in的使用
SELECT * FROM student WHERE sid IN (SELECT sid FROM (SELECT * FROM sc AS a WHERE cid IN (SELECT cid FROM sc WHERE sid = 01)) b GROUP BY sid HAVING COUNT(cid) = (SELECT COUNT(cid) FROM sc c WHERE sid = 01)) AND sid != 01 ; SELECT * FROM student WHERE sid IN (SELECT sid FROM (SELECT * FROM sc AS a WHERE cid IN (SELECT cid FROM sc WHERE sid = 01)) b GROUP BY sid HAVING COUNT(cid) = (SELECT COUNT(cid) FROM sc c WHERE sid = 01)) AND sid != 01 ;
10.查詢沒學過"張三"老師講授的任一門課程的學生姓名
解題思路:1先要查詢出張三老師的教授課程,2而後利用not in 來找到學生的id
知識點:子查詢,not in,多重join
SELECT sname FROM student WHERE sid NOT IN ( SELECT sid FROM sc LEFT JOIN course ON sc.cid=course.cid LEFT JOIN teacher ON course.tid=teacher.tid WHERE tname='張三' )
11.查詢兩門及其以上不及格課程的同窗的學號,姓名及其平均成績
解題思路:題中提到了兩門及以上的不及格課程,所以考慮使用Groupby 和 having,題中還提到學生姓名以及平均成績,考慮到這裏還要求出平均成績,可是平均成績說明不是很清楚,
知識點:Group by ,having,以及子查詢在from子句中的使用
SELECT sname,s.sid,AVG(sc1.score) AS avg_score FROM (SELECT * FROM sc WHERE score < 60)sc1, student AS s WHERE sc1.sid=s.sid GROUP BY sc1.sid HAVING COUNT(sc1.cid)>=2;
12.檢索" 01 "課程分數小於 60,按分數降序排列的學生信息
解題思路:要求01課程小於60的學員信息,而後按照降序排列學員信息
知識點:就是很簡單的order by
SELECT s.* FROM sc,student AS s WHERE cid = '01' AND score <60 AND sc.sid = s.sid ORDER BY score DESC;
固然還有其餘解法,好比使用join,這裏就很少寫了
13.按平均成績從高到低顯示全部學生的全部課程的成績以及平均成績
解題思路:要按照平均成績降序排列,則須要使用group by,以及要顯示全部的課程信息,那麼就須要使用join來實現了
知識點:group by ,子查詢,join
SELECT s.*, avg_score FROM sc AS s LEFT JOIN (SELECT sc.sid,AVG(sc.score) AS avg_score FROM sc GROUP BY sc.sid ORDER BY avg_score DESC) r ON s.sid = r.sid ;
能夠發現這裏的作法,發現並無按照我想要的平均成績的從高到低來排序,因此就去排查一下緣由,發現這個錯誤是執行順序的關係。
正確作法
SELECT s.*, avg_score FROM sc AS s LEFT JOIN (SELECT sc.sid ,AVG(sc.score) AS avg_score FROM sc GROUP BY sc.sid ) r ON s.sid = r.sid ORDER BY avg_score DESC ;
這樣就能夠了,所以啊,sql執行順序仍是要牢記的
14.查詢各科成績最高分、最低分和平均分,以以下形式顯示:
以以下形式顯示:課程 ID,課程 name,最高分,最低分,平均分,及格率,中等率,
優良率,優秀率
及格爲>=60,中等爲:70-80,優良爲:80-90,優秀爲:>=90
要求輸出課程號和選修人數,查詢結果按人數降序排列,若人數相同,按課程號升序
排列
解題思路:這裏要把最高分,最低分,平均分,等多個維度,那麼就須要使用case when 語句了還有就是函數的使用
知識點:case when 別名的使用,以及函數的使用,和函數的嵌套使用,題目後邊還考到了多列排列的使用,先按照desc,後按照asc排列
SELECT cid AS 課程ID, COUNT(sid) AS 課程人數, MAX(score) AS 最高分, MIN(score) AS 最低分, AVG(score) AS 平均分, SUM(及格) / COUNT(sid) AS 及格率, SUM(中等) / COUNT(sid) AS 中等率, SUM(優良) / COUNT(sid) AS 優良率, SUM(優秀) / COUNT(sid) AS 優秀率 FROM (SELECT *, CASE WHEN score >= 60 THEN 1 ELSE 0 END AS 及格, CASE WHEN score >= 70 AND score < 80 THEN 1 ELSE 0 END AS 中等, CASE WHEN score >= 80 AND score < 90 THEN 1 ELSE 0 END AS 優良, CASE WHEN score >= 90 THEN 1 ELSE 0 END AS 優秀 FROM sc) a GROUP BY cid ORDER BY COUNT(sid) DESC, cid ;
特別長,可是知識很簡單,就是case when語句的使用
15.按各科成績進行排序,並顯示排名, Score 重複時保留名次空缺
解題思路:兩張成績錶鏈接,而後按照成績大小作一個排名
知識點:排序相關知識
SELECT a.*, COUNT(a.score) AS 排名 FROM sc AS a LEFT JOIN sc AS b ON a.cid = b.cid AND a.score < b.score GROUP BY a.cid, a.sid ORDER BY a.cid, 排名 ;
15.1 按各科成績進行行排序,並顯示排名, Score 重複時合併名次
解題思路:相比於上一題這裏多了一個合併名次的事情,所謂名次合併,意思是兩我的的成績一致按照一個名次來,好比兩個成績同樣的排名第一,下一個排名第二的就當作第三名
SELECT a.*, COUNT(b.score)+1 AS 排名 FROM sc AS a LEFT JOIN sc AS b ON a.cid = b.cid AND a.score < b.score GROUP BY a.cid, a.sid ORDER BY a.cid, 排名 ;
16.查詢學生的總成績,並進行排名,總分重複時保留名次空缺
解題思路:和15題差很少,不過我要引入一個用戶變量
知識點:用戶變量的使用
SELECT a.*, @rank := @rank + 1 AS rank FROM (SELECT sid, SUM(score) FROM sc GROUP BY sid ORDER BY SUM(score) DESC) a, (SELECT @rank := 0) b ;
16.1 查詢學生的總成績,並進行排名,總分重複時不保留名次空缺
解題思路:這一題,不熟練,參考了前輩們的作法
知識點:用戶變量,子查詢
SELECT a.*, CASE WHEN @fscore = a.sumscore THEN @rank WHEN @fscore := a.sumscore THEN @rank := @rank + 1 END AS 排名 FROM (SELECT sc.sid, SUM(score) AS sumscore FROM sc GROUP BY sid ORDER BY SUM(score) DESC) AS a, (SELECT @rank := 0, @fscore := NULL) AS t ;
17. 統計各科成績各分數段人數:課程編號,課程名稱,[100-85],[85-70],[70-60],[60-0] 及所佔百分比
解題思路:這個題和以前的那一題很像,都是使用case when 語句,而後加一個join
知識點:join case when,以及
SELECT sc.cid AS 課程編號, cname AS 課程名稱, SUM( CASE WHEN score >= 0 AND score <= 60 THEN 1 ELSE 0 END ) AS '[60-0]', SUM( CASE WHEN score >= 0 AND score <= 60 THEN 1 ELSE 0 END ) / COUNT(sid) AS '[60-0]百分比', SUM( CASE WHEN score >= 60 AND score <= 70 THEN 1 ELSE 0 END ) AS '[70-60]', SUM( CASE WHEN score >= 60 AND score <= 70 THEN 1 ELSE 0 END ) / COUNT(sid) AS '[70-60]百分比', SUM( CASE WHEN score >= 70 AND score <= 85 THEN 1 ELSE 0 END ) AS '[85-70]', SUM( CASE WHEN score >= 70 AND score <= 85 THEN 1 ELSE 0 END ) / COUNT(sid) AS '[85-70]百分比', SUM( CASE WHEN score >= 85 AND score <= 100 THEN 1 ELSE 0 END ) AS '[100-85]', SUM( CASE WHEN score >= 85 AND score <= 100 THEN 1 ELSE 0 END ) / COUNT(sid) AS '[100-85]百分比' FROM sc JOIN course ON sc.cid = course.cid GROUP BY sc.cid, cname ;
18.查詢各科成績前三名的記錄
解題思路:按照課程id和學生id來分組,而後合併兩個sc表,找到第一個表的成績比第二個表成績低的的值,而後排序
知識點: join groupby以及having的使用,固然還有order by的使用
SELECT a.*,COUNT(b.score) +1 AS ranking FROM SC AS a LEFT JOIN SC AS b ON a.cid = b.cid AND a.score<b.score GROUP BY a.cid,a.sid HAVING ranking <= 3 ORDER BY a.cid,ranking;
19.查詢每門課程被選修的學生數
解題思路:就是很簡單的按照cid分組,而後計算每一個組裏面的學生人數,因爲前面幾題都是想了好久,遇到這題,我居然不敢相信這麼簡單
知識點:groupby
SELECT cid,COUNT(sid) AS num FROM sc GROUP BY cid;
20.查詢出只選修兩門課程的學生學號和姓名
解題思路:查詢選擇了兩門課的學生,而後鏈接student表,還算是比較基礎的題
知識點:groupby having join
SELECT sc.sid,sname FROM sc INNER JOIN student ON sc.sid = student.sid GROUP BY sc.sid HAVING COUNT(sc.cid) = 2;
21. 查詢男生、女生人數
解題思路:男女生人數這個毫無疑問考的是groupby 還有就是分組之後的count,或者可使用case when
知識點:groupby,或者 case when
SELECT ssex,COUNT(ssex) as FROM student GROUP BY ssex;
SELECT SUM(CASE WHEN ssex='男' THEN 1 ELSE 0 END)AS 男生人數, SUM(CASE WHEN ssex='女' THEN 1 ELSE 0 END) AS 女生人數 FROM student;
固然這裏不完美的,可使用count(sid)-男生人數,有不少的方式。
22. 查詢名字中含有「風」字的學生信息
解題思路:很簡單的一題,就是考察通配符,而考察點是是否有風
知識點:通配符%
SELECT * FROM student WHERE sname LIKE '%風%';
23查詢同名同性學生名單,並統計同名人數
解題思路:同名同性,咱們須要的是count(sname)>1,還要作一步篩選。這裏有一個小坑,開始的時候我覺得是同名同姓,中國文化博大精深啊
知識點:having,groupby
SELECT sname,COUNT(sname) AS 同名人數 FROM student GROUP BY sname HAVING 同名人數>1;
因爲這個數據表中沒有同名的人數,因此顯示結果如上。
24.查詢 1990 年出生的學生名單
解題思路:很簡單的題,可是我仍是作錯了
知識點:通配符
SELECT sname FROM student WHERE sage LIKE '1990%';
本覺得能夠很快的執行併產生結果,可是沒想到報錯了,看一下報錯信息,睡是datetime error,這個是什麼緣由呢,咱們看一下,以前創表的語句
原來本來的建表的時候就是設置了datetime類型,那這裏就要使用date函數了,這裏對date函數作一些介紹
網上搜的圖
我以爲上面的圖可以很好的說明經常使用的時間函數處理,無非就是hour(小時),minute(分鐘),second(秒),day(天),week(周),month(月),quarter(季度),year(年度)
那麼這一題,顯然就是要使用year了
SELECT * FROM student WHERE YEAR(sage) LIKE '1990%';
好的,很完美的解決了問題
25.查詢每門課程的平均成績,結果按平均成績降序排列,平均成績相同時,按課程編
號升序排列
解題思路:按照課程分組,而後求分組之後的平均值。而後外加一個排序,排序順序按照課程id升序排列
知識點:group by ,order by
SELECT cid,AVG(score) FROM sc GROUP BY cid ORDER BY AVG(score) DESC,cid;
因爲這個表裏面只有3門課,因此這裏顯示不出來,若是有不少數據,而後又剛好有相同的id
的時候應該就能夠看出不一樣了
26.查詢平均成績大於等於 85 的全部學生的學號、姓名和平均成績
解題思路:按照學生id分組,而後求平均分,而後用having語句判斷平均分大於等於85,又由於要查詢學生姓名所以可使用join,或者直接使用笛卡爾積,可是笛卡爾積對於數據量比較大的時候不宜使用
知識點:having,groupby,join
SELECT sc.sid,sname,AVG(score) AS 平均成績 FROM sc,student WHERE sc.sid = student.sid GROUP BY sc.sid HAVING 平均成績>= 85;
或者
SELECT sc.sid,sname,AVG(score) AS 平均成績 FROM sc INNER JOIN student ON sc.sid = student.sid GROUP BY sc.sid HAVING 平均成績>= 85;
結果都是第同樣的,可是數據裏大的時候我會使用第二種解法
27.查詢課程名稱爲「數學」,且分數低於 60 的學生姓名和分數
解題思路:和上一題同樣,可使用join,也能夠直接使用笛卡爾積,可是要使用三張表,因此最好仍是使用join
知識點:多重join的使用
SELECT sname, score FROM course AS c INNER JOIN sc ON c.cid = sc.cid AND c.cname = '數學' AND sc.score < 60 INNER JOIN student AS s ON sc.sid = s.sid ;
28. 查詢全部學生的課程及分數狀況(存在學生沒成績,沒選課的狀況)
解題思路:要把學生的姓名展現出來,因此使用join
知識點:join的使用
SELECT sname, sc.cid, score FROM sc INNER JOIN student AS s ON sc.sid = s.sid ;
29.查詢任何一門課程成績在 70 分以上的姓名、課程名稱和分數
解題思路:就是在上一題的基礎上,加上一個where條件判斷,或者直接在join on後邊判斷
知識點:join加上條件判斷
SELECT sname, sc.cid, score FROM sc INNER JOIN student AS s ON sc.sid = s.sid AND score > 70 ;
或者
SELECT sname, sc.cid, score FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE score > 70 ;
結果是同樣的,至於二者的區別,能夠參考下面這篇文章https://blog.csdn.net/weixin_40539892/article/details/90263677
總結起來就是inner join後邊時兩個作法是沒有區別的,可是若是是left join這種就會有多餘的出來了,這是由於使用join之後會生成一個虛擬表,而使用where是在這張虛擬表的基礎上進行篩選,因此結果可能不同。這個值得注意。
30.查詢不及格的課程
解題思路:這個其實和上面一題是同一個考法,不詳細展開,惟一的區別就是隻查詢課程,因此就是要distinct,或者groupby
知識點:join,
SELECT sc.cid FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE score < 60 GROUP BY sc.cid
第二種使用distinct
SELECT DISTINCT sc.cid FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE score < 60 ;
31.查詢課程編號爲 01 且課程成績在 80 分以上的學生的學號和姓名
解題思路:首先確定須要join把兩個表連起來,而後使用條件查詢課程id爲01且成績大於80
知識點:join where
SELECT sc.sid,sname FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE sc.cid = 01 AND score >= 80;
32.求每門課程的學生人數
解題思路:就是簡單的按照課程分組而後求sid的人數
知識點:group by ,count
SELECT cid,COUNT(sid) AS 人數 FROM sc GROUP BY cid;
33.成績不重複,查詢選修「張三」老師所授課程的學生中,成績最高的學生信息及其成績
解題思路:這題首先要找到張三老師所授課程,而後找到選擇這門課程的學生,在成績按照從大到小的順序排列,而後只取最高的成績,固然還須要使用子查詢
知識點:join,limit
SELECT s.*, score FROM student AS s INNER JOIN sc ON s.sid = sc.sid WHERE sc.cid = (SELECT cid FROM teacher AS t INNER JOIN course AS c ON t.tid = c.cid AND tname = '張三') ORDER BY score DESC LIMIT 1 ;
如今慢慢有點感受了,可以很快寫出來,果真這種語言相關的仍是要多敲代碼,不要怕錯,就是烏龜的速度,只要一直往前也有機會超過兔子
34.成績有重複的狀況下,查詢選修「張三」老師所授課程的學生中,成績最高的學生
信息及其成績
解題思路:有重複成績,咱們就選擇一個最大成績而後使用子查詢,讓成績在各科成績的最大值裏面作篩選
知識點:多重join,以及子查詢的應用
SELECT student.*, sc.cid, score FROM student INNER JOIN sc ON student.sid = sc.sid JOIN course ON sc.cid = course.cid JOIN teacher ON course.tid = teacher.tid WHERE tname = '張三' AND score IN (SELECT MAX(score) FROM sc INNER JOIN course ON sc.cid = course.cid JOIN teacher ON course.tid = teacher.tid WHERE tname = '張三') ;
因爲我建立的表格裏面沒有重複的成績,因此返回結果沒有發生變化
35.查詢不一樣課程成績相同的學生的學生編號、課程編號、學生成績
解題思路:首先join兩張表,而後作篩選1成績相同,2課程id不相同
知識點:join,以及where的使用
SELECT DISTINCT a.* FROM sc AS a INNER JOIN sc AS b WHERE a.score = b.score AND a.cid != b.cid ;
因爲可能使用的是inner join,因此可能會有不少重複值,所以我用了一個distinct的作法。
36. 查詢每門成績最好的前兩名
解題思路:這題和前面有一題有很類似的地方,就是找到大於某個成績只有兩人就是前兩名
知識點:關聯子查詢
SELECT * FROM sc WHERE (SELECT COUNT(*) FROM sc AS a WHERE sc.cid = a.cid AND sc.score < a.score) < 2 ORDER BY cid ASC, sc.score DESC ;
我以爲這個題仍是相對來講好理解的,一樣的查詢前3名等等,只需改一個數字。
37. 統計每門課程的學生選修人數(超過 5 人的課程才統計)。
解題思路:按照課程分組,而後count人數,使用having作一個篩選
知識點:groupby having
SELECT cid, COUNT(sid) FROM sc GROUP BY cid HAVING COUNT(sid) > 5 ;
38.檢索至少選修兩門課程的學生學號
解題思路:和上一題基本相似按照學生id分組而後count cid,篩選出大於等於2的學生
知識點:groupby having
SELECT sid, COUNT(cid) FROM sc GROUP BY sid HAVING COUNT(cid) >= 2 ;
39.查詢選修了所有課程的學生信息
解題思路:一樣的咱們要知道總共有多少門課,不光是爲了回答這一道題,可能真實狀況會有不少的課,那麼就須要把course表中全部的課程計數,還要求學生信息,那就須要使用join了
知識點:join,where,子查詢
SELECT s.* FROM sc INNER JOIN student AS s ON sc.sid = s.sid WHERE cid = (SELECT COUNT(*) FROM course) ;
40.查詢各學生的年齡,只按年份來算
解題思路:這題開始就要使用時間函數了,不難,還算比較簡單
知識點:date函數的使用
SELECT sname, YEAR(NOW()) - YEAR(sage) AS 年紀 FROM student ;
41. 按照出生日期來算,當前月日 < 出生年月的月日則,年齡減一
解題思路:這個可使用case when語句,而後使用時間戳求差值
知識點:case when ,year,date_format
SELECT sname, CASE WHEN ( DATE_FORMAT(NOW(), '%m-%d') - DATE_FORMAT(sage, '%m-%d') ) < 0 THEN YEAR(NOW()) - YEAR(sage) + 1 ELSE YEAR(NOW()) - YEAR(sage) END AS 年齡 FROM student ;
42.查詢本週過生日的學生
解題思路:使用week函數
知識點:week,now
SELECT sname FROM student WHERE WEEK(sage) = WEEK(NOW());
能夠發現沒有結果,爲了驗證準確性,咱們把student表格單獨拉出來
SELECT * FROM student ;
能夠看到果真沒有,那麼爲了進一步驗證,咱們向student表中新增一行數據
INSERT INTO Student VALUES('09' , '關羽' , '1990-07-15' , '男'); SELECT * FROM student ;
看一下執行結果
在執行如下咱們以前的語句
ok看來語句是沒有毛病的,我也不知道爲啥非要驗證如下,多是強迫症吧。。。
43. 查詢下週過生日的學生
解題思路:好的嘛,下週過生日,表明着在上題的基礎上再加1
知識點:week,now
SELECT sname FROM student WHERE WEEK(sage) = WEEK(NOW()) + 1 ;
固然仍是沒有結果的,不過這裏就不作測試了
44.查詢本月過生日的學生
解題思路:基本相似的操做,使用month函數
知識點:month,now
SELECT sname, sage FROM student WHERE MONTH(sage) = MONTH(NOW());
45.查詢下月過生日的學生
解題思路:一樣的套路,一樣的解法
知識點:month,now
SELECT sname, sage FROM student WHERE MONTH(sage) = MONTH(NOW()) + 1 ;
哇哦,不知不覺間就到了最後一題了,這裏給我印象最深的是那幾個須要排序的題,我以爲排序的題,要好好琢磨,爭取可以很快的寫出來。
人果真都是有惰性的,這一篇沒想到拖了這麼久,不過可以在工做休息之餘寫完這篇文仍是很開心的,接下來,要繼續刷題,下一篇應該就是牛客網和leetcode上面的題了。加油!
話說寫了這麼長的文,不給個贊嗎?