SQL的聚合函式、分組、子查詢及組合查詢用法
聚合函式:
SQL中提供的聚合函式可以用來統計、求和、求最值等等。
分類:
–COUNT:統計行數量
–SUM:獲取單個列的合計值
–AVG:計算某個列的平均值
–MAX:計算列的最大值
–MIN:計算列的最小值
首先,建立資料表如下:
執行列、行計數(count):
標準格式
SELECT COUNT(<計數規範>) FROM <表名>
其中,計數規範包括:
- * :計數所有選擇的行,包括NULL值;
- ALL 列名:計數指定列的所有非空值行,如果不寫,預設為ALL;
- DISTINCT 列名:計數指定列的唯一非空值行。
例,計算班裡共有多少學生:
SELECT COUNT(*) FROM t_student;
也可加入篩選條件,如求女學生數目:
SELECT COUNT(*) FROM t_student WHERE student_sex='女';
如果要計算班級數目,就需要用到DISTINCT:
SELECT COUNT(DISTINCT student_class) FROM t_student;
DISTINCT即去重,如果不加DISTINCT則結果為錶行數——5。
返回列合計值(SUM):
注:sum只要ALL與DISTINCT兩種計數規範,無*。
計算學生年齡之和:
SELECT SUM(student_age) FROM t_student;
返回列平均值(AVG):
計算學生平均年齡:
SELECT AVG(student_age)FROM t_student;
返回最大值/最小值(MAX/MIN):
求年齡最大的學生資訊(最小值同理):
SELECT MAX(student_age) FROM t_student;
注:這裡只能求出最大年齡,要想顯示年齡最大的學生全部資訊,需要用到之後的子查詢。
資料分組(GROUP BY):
SQL中資料可以按列名分組,搭配聚合函式十分實用。
例,統計每個班的人數:
SELECT student_class,COUNT(ALL student_name) AS 總人數 FROM t_student GROUP BY (student_class);
AS為定義別名,別名的使用在組合及聯接查詢時會有很好的效果,之後再說。
分組中也可以加入篩選條件WHERE,不過這裡一定要注意的是,執行順序為:WHERE過濾→分組→聚合函式。牢記!
統計每個班上20歲以上的學生人數:
SELECT student_class,COUNT(student_name) AS 總人數 FROM t_student WHERE student_age >20 GROUP BY (student_class);
HAVING過濾條件:
之前說了分組操作、聚合函式、WHERE過濾的執行順序,那如果我們希望在聚合之後執行過濾條件怎麼辦?
例,我們想查詢平均年齡在20歲以上的班級
能用下面的語句嗎?
SELECT student_class, AVG(student_age) FROM t_student WHERE AVG(student_age)>20 GROUP BY student_class;
結果會出錯。正因為聚合函式在WHERE之後執行,所以這裡在WHERE判斷條件里加入聚合函式是做不到的。
這裡使用HAIVING即可完成:
SELECT student_class,AVG(student_age) AS 平均年齡 FROM t_student GROUP BY (student_class) HAVING AVG(student_age)>20;
這裡再囉嗦一句
SQL的執行順序:
–第一步:執行FROM
–第二步:WHERE條件過濾
–第三步:GROUP BY分組
–第四步:執行SELECT投影列
–第五步:HAVING條件過濾
–第六步:執行ORDER BY 排序
子查詢:
為什麼要子查詢?
現有一資料表如下:
根據之前的知識我們可以查出每門科目的最高分,但是要想查出取得最高分的學生資訊就做不到了。這時就需要用到子查詢來取得完整的資訊。
什麼是子查詢?子查詢就是巢狀在主查詢中的查詢。
子查詢可以巢狀在主查詢中所有位置,包括SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY。
但並不是每個位置巢狀子查詢都是有意義並實用的,這裡對幾種有實際意義的子查詢進行說明。
現有表兩張:一張學生表、一張班表。id相關聯
在SELECT中巢狀:
學生資訊和班級名稱位於不同的表中,要在同一張表中查出學生的學號、姓名、班級名稱:
SELECT s.student_id,s.student_name,(SELECT class_name FROM t_class c WHERE c.class_id=s.class_id) FROM t_student s GROUP BY s.student_id;
* 首先這條SQL語句用到了別名,寫法為在FORM的表名後加上某個字元比如FROM t_student s,這樣在之後呼叫t_student的某一列時就可以用s.student_id來強調此列來源於對應別名的那張表。
別名在子查詢及聯接查詢中的應用有著很好效果,當兩張表有相同列名或者為了加強可讀性,給表加上不同的別名,就能很好的區分哪些列屬於哪張表。
還有種情況就是在子查詢或聯接查詢時,主查詢及子查詢均為對同一張表進行操作,為主、子查詢中的表加上不同的別名能夠很好的區分哪些列的操作是在主查詢中進行的,哪些列的操作是在子查詢中進行的,下文會有例項說明。
接下來回到上面的SQL語句中,可以看出本條子查詢的巢狀是在SELECT位置(括號括起來的部分),它與學號、學生姓名以逗號分隔開並列在SELECT位置,也就是說它是我們想要查出的一列,
子查詢中查出的是,班級表中的班級id與學生表中的班級id相同的行,注意 WHERE c.class_id=s.class_id 這裡就是別名用法的一個很好的體現,區分開了兩張表中同樣列名的列。
結果:
最後的GROUP BY可以理解為對重複行的去重,如果不加:
在WHERE中巢狀:
現要查出C語言成績最高的學生的資訊:
SELECT * FROM t_student WHERE student_subject='C語言' AND student_score>=ALL (SELECT student_score FROM t_student WHERE student_subject='C語言') ;
結果:
這裡出現了一個ALL,其為子查詢運算子
分類:
–ALL運算子
和子查詢的結果逐一比較,必須全部滿足時表示式的值才為真。
–ANY運算子
和子查詢的結果逐一比較,其中一條記錄滿足條件則表示式的值就為真。
–EXISTS/NOT EXISTS運算子
EXISTS判斷子查詢是否存在資料,如果存在則表示式為真,反之為假。NOT EXISTS相反。
在子查詢或相關查詢中,要求出某個列的最大值,通常都是用ALL來比較,大意為比其他行都要大的值即為最大值。
要查出C語言成績比李四高的學生的資訊:
SELECT * FROM t_student WHERE student_subject='C語言' AND student_score >(SELECT student_score FROM t_student WHERE student_name='李四' AND student_subject='C語言');
通過上面兩例,應該可以明白子查詢在WHERE中巢狀的作用。通過子查詢中返回的列值來作為比較物件,在WHERE中運用不同的比較運算子來對其進行比較,從而得到結果。
現在我們回到最開始的問題,怎麼查出每門課最高成績的學生的資訊:
SELECT * FROM t_student s1 WHERE s1.student_score >= ALL(SELECT s2.student_score FROM t_student s2 WHERE s1.`student_subject`=s2.student_subject);
這裡就是上文提到的別名的第二種用法,主、子查詢對同一張表操作,區分開位於內外表中相同的列名。
結果:
子查詢的分類:
–相關子查詢
執行依賴於外部查詢的資料。
外部查詢返回一行,子查詢就執行一次。
–非相關子查詢
獨立於外部查詢的子查詢。
子查詢總共執行一次,執行完畢後後將值傳遞給外部查詢。
上文提到的例子中,第一個例子求學生對應班級名的即為相關子查詢,其中WHERE c.class_id=s.class_id 即為相關條件。其他的例子均只對一張表進行操作,為非相關子查詢。
需要注意的是相關子查詢主查詢執行一回,子查詢就執行一回,十分耗費時間,尤其是當資料多的時候。
組合查詢:
通過UNION運算子來將兩張表縱向聯接,基本方式為:
SELECT 列1 , 列2 FROM 表1 UNION SELECT 列3 , 列4 FROM 表2;
UNION ALL為保留重複行:
SELECT 列1 , 列2 FROM 表1 UNION ALL SELECT 列3 , 列4 FROM 表2;
組合查詢並不是太實用,所以這裡只是簡單提一下,不舉出例子了。
上文說過相關子查詢不推薦使用,組合查詢又用的少之又少,那需要關聯的多張表我們怎麼做?
這就是下一篇博文要詳細說明的SQL的重點表聯接、聯接查詢。而此篇博文目的是為了對巢狀查詢、別名的用法等等打下基礎,畢竟只是寫法變了,思路還是相似的。
感謝您的瀏覽,希望能對您有所幫助。