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的重點表聯接、聯接查詢。而此篇博文目的是為了對嵌套查詢、別名的用法等等打下基礎,畢竟只是寫法變了,思路還是相似的。
 
感謝您的瀏覽,希望能對您有所幫助。


免責聲明!

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



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