sql分組函數使用

sql分組函數使用

在實際SQL應用中,經常需要進行分組聚合,即將查詢對象按一定條件分組,然後對每一個組進行聚合分析。

8.3.1 GROUP BY子句創建分組

創建分組是通過GROUP BY子句實現的。與WHERE子句不同,GROUP BY子句用於歸納信息類型,以彙總相關數據。而爲什麼要使用GROUP BY子句創建分組呢?可通過下面這個簡單例子來說明。

實例17 單一分組的查詢

假如要從TEACHER表中查詢所有男教師的平均工資,用前面介紹的聚合函數AVG(),實現代碼如下:

SELECT AVG(SAL) AS boyavg_sal

FROM     TEACHER

WHERE   TSEX='男'

運行結果如圖8.18所示。

圖8.18 TEACHER表中查詢所有男教師的平均工資

而如果同時需要查詢所有女教師的平均工資,該如何處理呢?顯然,採用上述方法只能在WHERE子句中改變查詢條件,重新查詢。而如果要在一次查詢中,同時得到二者的查詢結果,就需要以性別爲基準,將表中的所有數據記錄分組,即男教師組和女教師組,並分別對兩組數據進行分析,即計算工資(SAL列)的平均值。

實現上述功能,就需要使用分組子句GROUP BY。包括GROUP BY子句的查詢就稱爲組合查詢。語法如下。

SELECT                              column, SUM(column)

FROM             table

GROUP BY        column

說明:GROUP BY子句依據column列裏的數據對行進行分組,即具有相同的值的行被劃爲一組。它一般與聚合函數同時使用。當然,這裏的SUM()函數也可以是其他聚合函數。所有的組合列(GROUP BY子句中列出的列)必須是來自FROM子句列出的表,不能根據實際值、聚合函數結果或者其他表達式計算的值來對行分組。

實例18 GROUP BY子句分組查詢

從TEACHER表中查詢所有男教師的平均工資和所有女教師的平均工資,實現代碼如下。

SELECT           TSEX+'教師'AS TEACHER, AVG(SAL) AS avg_sal

FROM                                 TEACHER

GROUP BY        TSEX

運行結果如圖8.19所示。

圖8.19 TEACHER表中所有男教師和所有女教師的平均工資

下面分析一下DBMS執行該實例的步驟。

     DBMS首先執行FROM子句,將表TEACHER作爲中間表。

     如果有WHERE子句,則根據其中的搜索條件,從中間表中去除那些值爲False的列。這裏沒有WHERE子句,所以跳過該步。

     根據GROUP BY子句指定的分組列即TSEX,將中間表中的數據進行分組。這裏TSEX只有“男”和“女”,因此中間表中的數據被分成了兩組,一組中TSEX的值爲“男”,另一組中TSEX的值爲“女”。

     爲每個行組計算SELECT子句中的值,併爲每組生成查詢結果中的一行。對於TSEX值爲“男”的行組,SELECT子句中首先執行“TSEX+'教師'”,得到“男教師”列值,再執行“AVG(SAL)”,求得該行組中的SAL的均值,將這兩個值作爲結果表中的一條記錄。同樣,對TSEX值爲“女”的行組,進行類似的操作得到另一條記錄。

8.3.2 GROUP BY子句根據多列組合行

上節介紹的GROUP BY子句進行組合查詢,在GROUP BY子句中只有一列,它是組合查詢的最簡單形式。如果表中的行組依賴於多列,只要在查詢的GROUP BY子句中,列出定義組所需的所有列即可。

實例19 GROUP BY子句根據多列組合行

從TEACHER表中查詢各個系男教師和女教師的人數。實現代碼:

SELECT           DNAME,TSEX, COUNT(*) AS TOTAL_NUM

FROM                                 TEACHER

GROUP BY        DNAME,TSEX

ORDER BY        DNAME

運行結果如圖8.20所示。

圖8.20 TEACHER表中各系男教師和女教師的人數

從結果中可以發現,只有計算機系列出了男教師和女教師的人數。而別的系,只列出了一個值,這是因爲,在TEACHER表中,這些系中的教師只有一種性別,如生物系只有兩個女教師,而沒有男教師,系統就認爲該行記錄爲NULL,所以生物系的男教師的人數記錄就不包含在結果表中。

8.3.3 ROLLUP運算符和CUBE運算符

在使用GROUP BY子句根據多列組合行時,可以在GROUP BY子句中使用ROLLUP運算符和CUBE運算符,擴展查詢結果。兩者的主要不同在於,CUBE運算符擴展的信息要比ROLLUP運算符多,下面結合具體的實例講解二者的使用及區別。

1.ROLLUP運算符的使用

實例20 使用ROLLUP運算符擴查詢

使用ROLLUP運算符擴展實例19查詢結果。實現代碼:

SELECT           DNAME,TSEX, COUNT(*) AS TOTAL_NUM

FROM                                 TEACHER

GROUP BY        DNAME,TSEX WITH ROLLUP

ORDER BY         DNAME

運行結果如圖8.21所示。

圖8.21 ROLLUP運算符擴展的組合查詢結果

與實例19相比,增加了7行數據。其中一行(結果中的第1行)爲TEACHER表中所有教師的總人數,另外還分別爲各系(DNAME)分組增加了一行(結果中的第3、5、8、10、12、14行),統計了各系教師的總人數。

實例21 改變GROUP BY子句中列的排列順序對ROLLUP運算符的影響

如果改變GROUP BY子句中列的排列順序,使用ROLLUP運算符會得到不同的結果,如下面的代碼:

SELECT           DNAME,TSEX, COUNT(*) AS TOTAL_NUM

FROM                                 TEACHER

GROUP BY        TSEX, DNAME WITH ROLLUP

ORDER BY         DNAME

運行結果如圖8.22所示。

圖8.22 依據系名排序後的結果

與8.3.2節實例相比,結果集中增加了3行記錄,其中一行(結果中的第3行)爲TEACHER表中所有教師的總人數,而另外兩行(結果中的第1行和第2行)爲性別(TSEX)分組的人數統計,即所有男教師的數量和所有女教師的數量。

2.CUBE運算符的使用

實例22 使用CUBE運算符擴展查詢

使用CUBE運算符擴展實例19查詢結果。實現代碼:

SELECT           DNAME,TSEX, COUNT(*) AS TOTAL_NUM

FROM                                 TEACHER

GROUP BY        DNAME,TSEX WITH CUBE

ORDER BY         DNAME

運行結果如圖8.23所示。

圖8.23 使用CUBE運算符擴展的組合查詢結果

從結果中可以發現,通過使用CUBE運算符,結果集中除了包含多列組合(DNAME和TSEX)的統計結果外,還包含了整表(TEACHER表)的統計結果和各單列(DNAME、TSEX)的統計結果。

8.3.4 GROUP BY子句中的NULL值處理

當GROUP BY子句中用於分組的列中出現NULL值時,將如何分組呢?按照前面的介紹,NULL不等於NULL(在WHERE子句中有過介紹)。然而,在GROUP BY子句中,卻將所有的NULL值分在同一組,即認爲它們是“相等”的。

實例23 GROUP BY子句中的NULL值處理

從TEACHER表中查詢所有的工資數及各工資的人數。實現代碼:

SELECT           SAL,COUNT(*) AS TOTAL_NUM

FROM                                 TEACHER

GROUP BY        SAL

ORDER BY         SAL

運行結果如圖8.24所示。

圖8.24 TEACHER表中所有的工資數及各工資的人數

可見,SAL列中的兩行NULL值被歸爲了一組。

8.3.5 HAVING子句

GROUP BY子句分組,只是簡單地依據所選列的數據進行分組,將該列具有相同值的行劃爲一組。而實際應用中,往往還需要刪除那些不能滿足條件的行組,爲了實現這個功能,SQL提供了HAVING子句。語法如下。

SELECT                             column, SUM(column)

FROM             table

GROUP BY       column

HAVING                              SUM(column) condition value

說明:HAVING通常與GROUP BY子句同時使用。當然,語法中的SUM()函數也可以是其他任何聚合函數。DBMS將HAVING子句中的搜索條件應用於GROUP BY子句產生的行組,如果行組不滿足搜索條件,就將其從結果表中刪除。

注意

前面介紹的有關WHERE子句的所有操作,如使用連接符、通配符、函數等,在HAVING子句中都可以使用。

實例24 HAVING子句的應用

從TEACHER表中查詢至少有兩位教師的系及教師人數。實現代碼:

SELECT           DNAME, COUNT(*) AS num_teacher

FROM                                 TEACHER

GROUP BY        DNAME

HAVING           COUNT(*)>=2

運行結果如圖8.25所示。

圖8.25 TEACHER表中至少有兩位教師的系及教師人數

8.3.6 HAVING子句與WHERE子句

HAVING子句和WHERE子句的相似之處在於,它也定義搜索條件。但與WHERE子句不同,HAVING子句與組有關,而不是與單個的行有關。

     如果指定了GROUP BY子句,那麼HAVING子句定義的搜索條件將作用於這個GROUP BY子句創建的那些組。

     如果指定WHERE子句,而沒有指定GROUP BY子句,那麼HAVING子句定義的搜索條件將作用於WHERE子句的輸出,並把這個輸出看作是一個組。

     如果既沒有指定GROUP BY子句也沒有指定WHERE子句,那麼HAVING子句定義的搜索條件將作用於FROM子句的輸出,並把這個輸出看作是一個組。

在SELECT語句中,WHERE和HAVING子句的執行順序不同。在本書的5.1.2節介紹的SELECT語句的執行步驟可知,WHERE子句只能接收來自FROM子句的輸入,而HAVING子句則可以接收來自GROUP BY子句、WHERE子句和FROM子句的輸入。

下面通過幾個實例講解HAVING子句和WHERE子句的不同作用。

實例25 HAVING子句和WHERE子句的不同作用

從TEACHER表中查詢有女教師的系及擁有的女教師數量。實現代碼:

SELECT           DNAME, COUNT(TSEX) AS num_girl

FROM                                 TEACHER

WHERE                               TSEX='女'

GROUP BY        DNAME

運行結果如圖8.26所示。

圖8.26 TEACHER表中具有女教師的系及擁有的女教師數量

可見得到了3個系,與TEACHER表中數據相吻合。如果在上例中不使用WHERE子句,而是使用HAVING子句,教師限制爲女教師,如下面的代碼:

SELECT           DNAME, COUNT(TSEX) AS num_girl

FROM                                 TEACHER

GROUP BY        DNAME

HAVING                              TSEX='女'

執行該代碼,系統會給出以下出錯提示信息。

Column 'TEACHER.TSEX' is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause.

不能把單個的TSEX的值應用於組,包括在HAVING子句中的列必須是組列。因此,在這種情況下,WHERE子句就不可能用HAVING子句代替。

在數據的分組聚合分析中,HAVING子句與WHERE子句也可以共存。WHERE子句在分組之前過濾數據,而HAVING子句則過濾分組後的數據。

實例26 HAVING子句與WHERE子句聯合使用

查詢至少有兩名女教師的系及擁有的女教師數量。實現代碼:

SELECT           DNAME, COUNT(TSEX) AS num_girl

FROM                                 TEACHER

WHERE                               TSEX='女'

GROUP BY        DNAME

HAVING           COUNT(TSEX)>=2

運行結果如圖8.27所示。

圖8.27 TEACHER表中至少有兩名女教師的系及擁有的女教師數量

這裏通過HAVING子句對分組結果進行搜索,去除了不滿足搜索條件(即只有一個教師的經濟管理系)的行。

通常情況下,HAVING子句都與GROUP BY子句一起使用,這樣就可以聚合相關數據,然後篩選這些數據,以進一步細化搜索。然而,如果沒有GROUP BY子句,HAVING子句也可以單獨使用。

實例27 HAVING子句的單獨使用

如下面的代碼:

SELECT           COUNT(TSEX) AS num_girl

FROM                                 TEACHER

WHERE                               TSEX='女'

HAVING       COUNT(TSEX)>4

運行結果如圖8.28所示。

圖8.28 單獨使用HAVING子句的查詢結果

上述代碼實現的功能實際上是從教師表中查詢所有女教師的數量,如果女教師的數量大於4,則將其作爲查詢結果,而如果數量少於或者等於4,那麼查詢結果將爲空值。當然,這種不使用GROUP BY子句而使用HAVING子句的情況,在實際應用中很少用到。

8.3.7 SELECT語句各查詢子句總結

至此,SELECT語句中的所有子句都介紹完了,它們在SELECT查詢語句中的排列順序及主要作用如表8-2所示。

表8-2                                                SELECT查詢語句及其所有子句

順 序 號

子句關鍵詞

子 句 功 能

1

SELECT

從指定表中取出指定的列的數據

2

FROM

指定要查詢操作的表

3

WHERE

用來規定一種選擇查詢的標準

4

GROUP BY

對結果集進行分組,常與聚合函數一起使用

5

HAVING

返回選取的結果集中行的數目

6

ORDER BY

指定分組的搜尋條件

如果在同一個SELECT查詢語句中,用到了表8-2所示的一些查詢子句,則各查詢子句的排列就依照它們的順序號由低到高的順序。因此,完整的SELECT查詢語句可以表示爲:

SELECT                                                  select_list

FROM                                                    table_source

[ WHERE                                                 search_condition ]

[ GROUP BY                          group_by_expression ]

[ HAVING                            search_condition ]

[ ORDER BY                          order_expression [ ASC | DESC ] ]

其中[ ]中的部分爲可選項。

實例28 在SELECT語句中綜合使用查詢子句

從TEACHER表中查詢至少有兩名女教師的系及擁有的女教師數量,並按女教師的數量升序的順序排列結果。實現代碼:

SELECT           DNAME, COUNT(TSEX) AS num_girl

FROM                                 TEACHER

WHERE                               TSEX='女'

GROUP BY        DNAME

HAVING       COUNT(TSEX)>=2

ORDER BY                            num_girl

運行結果如圖8.29所示。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章