原創文章,轉載請註明出處:http://www.cnblogs.com/weix-l/p/7521278.html;
html
如有錯誤,請評論指出,謝謝!mysql
1. 聚合函數(Aggregate Function)sql
MySQL(5.7 ) 官方文檔中給出的聚合函數列表(圖片)以下:數據結構
詳情點擊https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html 。函數
除非另有說明,不然聚合函數都會忽略空值(NULL values)。測試
2. 聚合函數的使用spa
聚合函數一般對 GROUP BY 語句進行分組後的每一個分組起做用,即,若是在查詢語句中不使用 GROUP BY 對結果集分組,則聚合函數就對結果集的全部行起做用。爲說明聚合函數的使用,現建立測試表 member 進行測試,member 的數據結構以下(使用 SELECT * FROM member 查詢所得):3d
1)對結果集直接使用聚合函數code
例如,使用聚合函數SUM () 計算全部會員(member) 的會費總和,則可以使用:htm
SELECT SUM(fee) AS total_fee FROM member #計算全部會員會費總和
查詢結果爲:
SUM 函數會對所有字段列 fee 進行求和。固然,也能夠求平均值、最大值等。
此外,也可使用 WHERE 語句進行限定條件的聚合查詢。例如,若是要查詢 country 爲 China 的會員會費之和,則爲:
SELECT SUM(fee) AS China_total_fee, country FROM member WHERE country = 'China'
結果顯示以下:
2)GROUP BY 對結果集分組後使用聚合函數——組內聚合
——將字段值相同的記錄歸爲一組,可用COUNT(*) 統計組內成員個數;
——以分組爲單位,對組內每一個成員使用聚合函數進行統計,即聚合函數是關於分組成員的函數。
試想,若是要從測試表中查詢每一個國家的會費總和呢?每一個國家的會費,即先將全部結果集按 country 字段進行分組,country 值相同的行歸爲一組,而後以組爲單位進行求和,這樣查詢的結果記錄數等於分組字段不一樣值的個數。總共有來自三個國家(China, US, UK)的會員,因此分組聚合查詢的結果記錄數爲3:
#查詢每一個國家的會費之和
SELECT SUM(fee) AS country_group_total_fee, country FROM member GROUP BY country
該查詢語句會計算每一個國家的會費之和,而後展現按每一個國家分組的查詢結果:
標準SQL( standard SQL) 和 MySQL 都提供 HAVING 語句對使用 GROUP BY 分組以後的結果進行條件篩選併產生新的結果集。例如,對於前述 1)中查詢中國會員會費總和的問題,可使用HAVING 語句:
#使用HAVING語句查詢中國會員會費總和
SELECT SUM(fee) AS country_group_total_fee, country FROM member GROUP BY country HAVING country = 'China'
結果和上面同樣:
這種方法與前述 1)中直接使用WHERE進行限定相比有些多此一舉,爲何呢?由於 country 在此是分組字段(group column),對分組字段使用 HAVING 再次進行限定則就顯得分組毫無心義,由於這時徹底能夠經過使用 WHERE 進行篩選後直接求和實現。那麼,能使用非聚合列(nonaggregated column) 爲限定條件嗎?答案是,不只沒有意義,並且不容許。非聚合列指的是沒有用聚合函數而是要查詢的表自己的字段,由於使用 GROUP BY 分組查詢後的聚合結果列中根本就不包含非聚合字段列,因此在解析SQL語句時根本找不到這個字段。好比,當你想獲取每一個國家性別爲 man 的會員的會費之和時可能嘗試在上面這個語句中使用 HAVING 對 sex 進行限定,像下面這樣:
#錯誤:嘗試使用HAVING 語句對非聚合字段進行限定
SELECT SUM(fee) AS country_group_total_fee FROM member m GROUP BY country HAVING m.sex = 'man'
執行後會報錯 Err 1054:
[Err] 1054 - Unknown column 'm.sex' in 'having clause',提示未知的列m.sex,即便此處使用別名進行說明也不行。那麼如何實現查詢每一個國家性別爲 man 的會員的會費之和呢?固然仍是使用WHERE 語句在 GROUP BY 進行分組以前就進行限定:
#在分組以前使用 WHERE 進行條件篩選
SELECT SUM(fee) AS country_group_total_fee, country FROM member WHERE sex = 'man' GROUP BY country
產生下面結果:
因此,HAVING 不能對分組自己起做用,但能夠對分組後的結果進行查詢限定,而限定的條件只能爲聚合列(aggregated column),聚合列指的是在 SELECT 列 (SELECT list)中使用聚合函數產生的列,例如,此處的SUM(fee) 就是聚合列。在HAVING 中對聚合列進行限定,能夠獲取知足必定條件的聚合列結果。例如,在上面獲取每一個國家會員費用之和後再限定查詢哪些會員費用之和超過10000,則可使用下面的SQL 語句:
#查詢會員費總和超過10000 的國家
SELECT SUM(fee) country FROM member GROUP BY country HAVING SUM(fee) > 10000
其結果就只剩下中國了:)
這是在標準SQL語句中的語法。在MySQL中擴展了HAVING 的用法,使其能夠接受聚合列的別名做爲限定條件,例如上面的要求使用別名的查詢語句爲:
#在HAVING 中使用別名
SELECT SUM(fee) AS country_group_total_fee, country FROM member GROUP BY country HAVING country_group_total_fee > 10000
其結果仍爲:
3)GROUP BY 按多個分組字段分組後使用聚合函數——細分組內聚合
若是使用一個分組字段分組後的聚合結果記錄數等於該分組字段不一樣值的個數,那麼,使用多個分組字段之後呢?例如,在上面的查詢的基礎上,若是想要查詢每一個國家男、女分別的會費總和時,可使用下面的語句:
#查詢每一個國家男、女會員的總和會費
SELECT SUM(fee) AS sex_and_country_group_total_fee, country, sex FROM member GROUP BY country,sex
結果以下:
從上面的結果能夠看出來,「中國的男性會員出的總會費最多,而英國的男性會員的總會費最少」。總共三個國家,若是隻按國家(country) 進行分組,只有三條記錄,若是再按性別 (sex) 分,則會在分組後的每一個組(也即每一行、每一條記錄)裏按性別的不一樣再進行細分,由於性別值只有兩種,因此每一個國家的分組又被分紅兩小組,則三個國家總共就有6小組(6 = 3 × 2),這樣最終也就會有6條記錄,如上圖示。
爲了解每一個細分小組的個數,在SELECT 查詢列的最後加上計算分組個數的聚合函數 COUNT(*):
#多分組字段分組,並統計每組個數
SELECT SUM(fee) AS sex_and_country_group_total_fee, country, sex, COUNT(*) AS row_num FROM member GROUP BY country, sex
結果以下:
上面的結果默認按靠近GROUP BY 的順序進行排序,但若是要指定排序一句,則可以使用ORDER BY ,例如,對上面的結果按 sex 排序:
#將分組結果按sex 排序
SELECT SUM(fee) AS sex_and_country_group_total_fee, country, sex, count(*) AS row_num FROM member GROUP BY country, sex ORDER BY sex
結果以下:
若是用其餘字段對結果再進行細分呢?原理與上述兩個字段進行分組時同樣的,只是分組的深度越多,很明顯結果的記錄行數也越多,但無論怎樣,你會發現每一條分組後的結果都是不同的,這正是分組結果的特徵,由於ORDER BY 自己就具備聚合功能,每一個聚合列的結果是經過分組歸類的結果,因此只有一條記錄。
那麼,若是用表的 主鍵 或 非空惟一性字段 進行分組,結果會怎樣呢?好比,在本測試表中,id 是其主鍵,name 是非空的具備惟一性約束的字段,下面分別是以 id 和 name 進行分組的MySQL 語句和結果:
#以主鍵id進行分組
SELECT SUM(fee) AS sex_and_country_group_total_fee, id, COUNT(*) AS row_num FROM member GROUP BY id
結果以下:
#以非空惟一性約束字段進行分組
SELECT SUM(fee) AS sex_and_country_group_total_fee, name, COUNT(*) AS row_num FROM member GROUP BY name
結果以下:
很顯然,這兩種分組的結果中聚合函數結果列是同樣的,每組的結果記錄行數也同樣,並且都爲1,這說明按主鍵或非空惟一性約束字段進行分組其結果相同,且結果就是表的所有每一行記錄。這樣作可能沒有太大意義,但有助於理解 GROUP BY 分組的原理。
3. 總結
1) 可直接對某個字段使用聚合函數,也可用 WHERE 語句篩選後對某個字段使用聚合函數;
2) 聚合函數一般做用於使用 GROUP BY 分組後的分組成員,用於統計每一個分組的數據;
3) 不能對沒有使用 GROUP BY 分組的聚合函數使用 HAVING 進行限定;
4) 可對使用 GROUP BY 分組查詢後的結果使用 HAVING 進行限定,其限定條件最好爲聚合函數列(自己或其餘聚合函數);
5) 可在使用 GROUP BY 分組前使用 WHERE 對結果進行篩選,在分組後使用 HAVING 對聚合函數列進行限定;
6) 可以使用 ORDER BY 對結果按照某個字段(任意字段或列,使用 GROUP BY 分組時也可以使用聚合函數列)進行排序;
7) 當按照主鍵或非空惟一性約束字段進行分組時,其結果爲整個表的所有記錄。
4. 參考文獻
[1]. MySQL 官方文檔 URL: https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html