MySQL版本:5.7+
本節介紹對值的集合進行操作的組合(聚合)函數。翻譯自:Aggregate (GROUP BY) Function Descriptions
一、MySQL 5.7中的聚合函數
MySQL 5.7中的聚合函數如下:
除非另有說明,否則組合函數會忽略NULL值。
如果在不包含Group By子句的語句中使用組合函數,就等效於對所有行進行分組。(個人理解是,結果總是只有一行。)關於這點的更多信息,后面的小節“MySQL處理Group By的方式”會講到。
聚合函數中,方差和標准差函數會對數值參數返回DOUBLE值。SUM()和AVG()對精確值參數(integer或DECIMAL)返回DECIMAL值,而對近似值參數(FLOAT或DOUBLE)返回DOUBLE值。
時間類型的參數對SUM()和AVG()無效。它們會把時間類型的值轉換成數字,丟棄第一個非數字字符后的所有信息)。如果要解決這個問題,先要將時間類型的值轉換為合適的數值單元,在執行聚合操作后,再轉換回時間值。如下所示:
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(time_col))) FROM tbl_name; SELECT FROM_DAYS(SUM(TO_DAYS(date_col))) FROM tbl_name;
諸如SUM()和AVG()這樣需要數值參數的函數,會對非數值參數做必要的強制轉換。而對於SET或ENUM值,強制轉換操作會導致使用基礎數值。
BIT_AND(),BIT_OR()和BIT_XOR()聚合函數執行位操作。它們需要BIGINT(64位整數)參數並返回BIGINT值。其他類型的參數將轉換為BIGINT並可能發生截斷。而在MySQL 8.0中,允許位操作采用二進制字符串類型參數(BINARY,VARBINARY和BLOB類型),詳見其手冊的12.12節。
二、聚合函數詳解
2.1 AVG()
AVG([DISTINCT] expr)
函數返回expr的平均值。
DISTINCT則用於返回expr的不同值的平均值。
如果沒有匹配的行,AVG()返回null。
2.2 COUNT()
COUNT(expr)
返回SELECT語句檢索的行中expr的非NULL值的計數。
返回結果是BIGINT值。
如果沒有匹配的行,count()返回0.
count(*)有些不同,它返回取回的行的行數的計數,無論它們是否包含NULL值。
對於諸如InnoDB之類的事務存儲引擎,存儲精確的行數是有問題的。多個事務可能同時發生,每個事務都可能影響計數。
所以InnoDB不在內部保留表的行數,因為並發事務可能同時“看到”不同數量的行。因此,SELECT COUNT(*)語句只計算當前事務可見的行。
在MySQL 5.7.18之前,InnoDB通過掃描聚集索引(clustered index)來處理SELECT COUNT(*)語句。從MySQL 5.7.18開始,InnoDB通過遍歷最小的可用二級索引來處理SELECT COUNT(*)語句,除非索引或優化器提示指示優化器使用不同的索引。如果不存在輔助索引,則掃描聚集索引。
如果索引記錄不完全在緩沖池中,那么處理select count(*)語句需要一些時間。為了更快地計算,可以創建一個計數表,讓應用程序根據插入和刪除操作更新它。但是,在數千個並發事務正在啟動對同一計數器表的更新的情況下,此方法可能無法很好地擴展。因此,如果大概的行數可以滿足需求,請使用SHOW TABLE STATUS。
對於MyISAM表,如果SELECT從一個表沒有檢索到其他列,並且沒有WHERE子句,而只返回COUNT(*)的結果,則COUNT(*)會被優化,可以快速返回。例如:
SELECT COUNT(*) FROM student;
此優化僅適用於MyISAM表,因為為此存儲引擎存儲了精確的行數,並且可以非常快速地訪問。COUNT(1)則僅在第一列定義為NULL時,受到相同額度優化。
2.3 COUNT(DISTINCT ...)
COUNT(DISTINCT expr,[expr...])
函數返回返回不相同且非NULL的expr值的行數。
如果沒有匹配的行,則COUNT(DISTINCT)返回0。
在MySQL中,您可以通過提供表達式列表,來獲取不包含NULL的不同表達式組合的數量。而在標准表達式中,必須在COUNT(DISTINCT ...)中對所有表達式進行連接。
2.4 GROUP_CONCAT()
GROUP_CONCAT([DISTINCT] expr [,expr ...] [ORDER BY {unsigned_integer | col_name | expr} [ASC | DESC] [,col_name ...]] [SEPARATOR str_val])
這個函數把來自同一個組的某一列(或者多列)的數據連接起來成為一個字符串。
如果沒有非NULL值,返回NULL。
示例如下:
/*001*/ /*成績表中只對學生ID分組*/ select SId, group_concat(cId),group_concat(score) from sc group by SId;
結果如下,並沒有排序
/*002*/ /*排序后連接,改變分隔符*/ select SId, group_concat(cId),group_concat(score order by score desc separator ' ') from sc group by SId;
結果如下:
至於對多個expr的連接,試了試,會把兩個字段無縫連在一起。
select SId, group_concat(cId,score),group_concat(score) from sc group by SId;
Group_Concat()的結果將截斷為group_concat_max_len系統變量所設置的最大長度,該變量的默認值為1024。
而返回值是非二進制或二進制字符串,具體取決於參數是非二進制還是二進制字符串。
返回的結果類型為TEXT或BLOB,除非group_concat_max_len小於或等於512,這種情況下,結果類型為VARCHAR或VARBINARY。
2.5 JSON_ARRAYAGG(col or expr)
將結果集聚合為單個JSON數組,其元素由參數列的值組成。此數組中元素的順序未定義。該函數作用於計算為單個值的列或表達式。
異常返回NULL。
示例如下:
2.6 JSON_OBJECTAGG(key,value)
兩個列名或表達式作為參數,第一個用作鍵,第二個用作值,並返回包含鍵值對的JSON對象。
如果結果不包含任何行,或者出現錯誤,則返回NULL。如果任何鍵名稱為NULL或參數數量不等於2,則會發生錯誤。
如何處理重復key,參考原文此處。
2.7 其余函數
位函數進行位操作。
標准差和方差函數,為了兼容有不同的函數名。
詳見原文檔。