1.?GROUP BY(聚合)函數
本章論述了用于一組數值操作的?group (集合)函數。除非另作說明,?group?函數會忽略?null?值。
假如你在一個不包含?ROUP BY子句的語句中使用一個?group函數 ,它相當于對所有行進行分組。
-
AVG([DISTINCT]?expr)
返回expr?的平均值。?DISTINCT?選項可用于返回?expr的不同值的平均值。
若找不到匹配的行,則AVG()返回?NULL?。
mysql>? SELECT?student_name,?AVG(test_score) ->? FROM?student ->? GROUP?BY?student_name;
-
BIT_AND(expr)
返回expr中所有比特的?bitwise AND?。計算執行的精確度為64比特(BIGINT)?。
若找不到匹配的行,則這個函數返回?18446744073709551615?。(這是無符號?BIGINT?值,所有比特被設置為?1)。
-
BIT_OR(expr)
返回expr?中所有比特的bitwise OR。計算執行的精確度為64比特(BIGINT)?。
若找不到匹配的行,則函數返回?0?。
-
BIT_XOR(expr)
返回expr?中所有比特的bitwise XOR。計算執行的精確度為64比特(BIGINT)?。
若找不到匹配的行,則函數返回?0?。
-
COUNT(expr)
返回SELECT語句檢索到的行中非NULL值的數目。
若找不到匹配的行,則COUNT()?返回?0?。
mysql>?SELECT?student.student_name,COUNT(*)->?FROM?student,course ->?WHERE?student.student_id=course.student_id->?GROUP?BY?student_name;
COUNT(*)?的稍微不同之處在于,它返回檢索行的數目, 不論其是否包含?NULL值。
SELECT?從一個表中檢索,而不檢索其它的列,并且沒有?WHERE子句時,?COUNT(*)被優化到最快的返回速度。例如:
mysql>?SELECT COUNT(*) FROM student;
這個優化僅適用于?MyISAM表,?原因是這些表類型會儲存一個函數返回記錄的精確數量,而且非常容易訪問。對于事務型的存儲引擎(InnoDB, BDB),?存儲一個精確行數的問題比較多,原因是可能會發生多重事物處理,?而每個都可能會對行數產生影響。
-
COUNT(DISTINCT?expr,[expr…])
返回不同的非NULL值數目。
若找不到匹配的項,則COUNT(DISTINCT)返回?0?。
mysql>?SELECT COUNT(DISTINCT results) FROM student;
在MySQL中,?你通過給定一個表達式列表而獲取不包含NULL?不同表達式組合的數目。在標準?SQL中,你將必須在COUNT(DISTINCT …)中連接所有表達式。
-
GROUP_CONCAT(expr)
該函數返回帶有來自一個組的連接的非NULL值的字符串結果。其完整的語法如下所示:
GROUP_CONCAT([DISTINCT]?expr?[,expr?…]
[ORDER BY {unsigned_integer?|?col_name?|?expr}
[ASC | DESC] [,col_name?…]]
[SEPARATOR?str_val])
mysql>?SELECT?student_name,->?GROUP_CONCAT(test_score)->?FROM?student->?GROUP?BY?student_name;
Or:
mysql>?SELECT?student_name,->?GROUP_CONCAT(DISTINCT?test_score->?ORDER?BY?test_score?DESC?SEPARATOR?'?')->?FROM?student->?GROUP?BY?student_name;
在MySQL中,你可以獲取表達式組合的連接值。你可以使用DISTINCT刪去重復值。假若你希望多結果值進行排序,則應該使用? ORDER BY子句。若要按相反順序排列,將?DESC (遞減)?關鍵詞添加到你要用ORDER BY?子句進行排序的列名稱中。默認順序為升序;可使用ASC將其明確指定。?? SEPARATOR?后面跟隨應該被插入結果的值中間的字符串值。默認為逗號?(‘,’)。通過指定SEPARATOR ”?,你可以刪除所有分隔符。
使用group_concat_max_len系統變量,你可以設置允許的最大長度。??程序中進行這項操作的語法如下,其中?val?是一個無符號整數:
SET [SESSION | GLOBAL] group_concat_max_len = val;
若已經設置了最大長度, 則結果被截至這個最大長度。
-
MIN([DISTINCT]?expr), MAX([DISTINCT]?expr)
返回expr?的最小值和最大值。?MIN()?和?MAX()?的取值可以是一個字符串參數;在這些情況下, 它們返回最小或最大字符串值。DISTINCT關鍵詞可以被用來查找expr?的不同值的最小或最大值,然而,這產生的結果與省略DISTINCT?的結果相同。
若找不到匹配的行,MIN()和MAX()返回?NULL?。
mysql>?SELECT?student_name,?MIN(test_score),?MAX(test_score)->?FROM?student->?GROUP?BY?student_name;
對于MIN()、?MAX()和其它集合函數,?MySQL當前按照它們的字符串值而非字符串在集合中的相關位置比較?ENUM和SET?列。這同ORDER BY比較二者的方式有所不同。這一點應該在MySQL的未來版本中得到改善。
-
STD(expr) STDDEV(expr)
返回expr?的總體標準偏差。這是標準?SQL?的延伸。這個函數的STDDEV()?形式用來提供和Oracle?的兼容性。可使用標準SQL函數?STDDEV_POP()?進行代替。
若找不到匹配的行,則這些函數返回?NULL?。
-
STDDEV_POP(expr)
返回expr?的總體標準偏差(VAR_POP()的平方根)。你也可以使用? STD()?或STDDEV(),?它們具有相同的意義,然而不是標準的?SQL。
若找不到匹配的行,則STDDEV_POP()返回?NULL。
-
STDDEV_SAMP(expr)
返回expr?的樣本標準差?( VAR_SAMP()的平方根)。
若找不到匹配的行,則STDDEV_SAMP()?返回?NULL?。
-
SUM([DISTINCT]?expr)
返回expr?的總數。 若返回集合中無任何行,則?SUM()?返回NULL。DISTINCT?關鍵詞可用于?MySQL 5.1?中,求得expr不同值的總和。
若找不到匹配的行,則SUM()返回?NULL。
-
VAR_POP(expr)
返回expr?總體標準方差。它將行視為總體,而不是一個樣本, 所以它將行數作為分母。你也可以使用?VARIANCE(),它具有相同的意義然而不是 標準的?SQL。
若找不到匹配的項,則VAR_POP()返回NULL。
-
VAR_SAMP(expr)
返回expr?的樣本方差。更確切的說,分母的數字是行數減去1。
若找不到匹配的行,則VAR_SAMP()返回NULL。
-
VARIANCE(expr)
返回expr?的總體標準方差。這是標準SQL?的延伸。可使用標準SQL?函數?VAR_POP()?進行代替。
若找不到匹配的項,則VARIANCE()返回NULL。
2.?GROUP BY修改程序
GROUP BY子句允許一個將額外行添加到簡略輸出端?WITH ROLLUP?修飾符。這些行代表高層(或高聚集)簡略操作。ROLLUP?因而允許你在多層分析的角度回答有關問詢的問題。例如,它可以用來向OLAP (聯機分析處理)?操作提供支持。
設想一個名為sales?的表具有年份、國家、產品及記錄銷售利潤的利潤列:
CREATE?TABLE?sales ( ????year????INT?NOT?NULL, ????country?VARCHAR(20)?NOT?NULL, ????product?VARCHAR(32)?NOT?NULL, ????profit??INT );
可以使用這樣的簡單GROUP BY,每年對表的內容做一次總結:
mysql>?SELECT?year,?SUM(profit)?FROM?sales?GROUP?BY?year;+------+-------------+ |?year?|?SUM(profit)?| +------+-------------+ |?2000?|????????4525?| |?2001?|????????3010?| +------+-------------+
這個輸出結果顯示了每年的總利潤, 但如果你也想確定所有年份的總利潤,你必須自己累加每年的單個值或運行一個加法詢問。
或者你可以使用?ROLLUP,?它能用一個問詢提供雙層分析。將一個?WITH ROLLUP修飾符添加到GROUP BY?語句,使詢問產生另一行結果,該行顯示了所有年份的總價值:
mysql>?SELECT?year,?SUM(profit)?FROM?sales?GROUP?BY?year?WITH?ROLLUP;+------+-------------+ |?year?|?SUM(profit)?| +------+-------------+ |?2000?|????????4525?| |?2001?|????????3010?| |?NULL?|????????7535?| +------+-------------+
總計高聚集行被年份列中的NULL值標出。
當有多重?GROUP BY?列時,ROLLUP產生的效果更加復雜。這時,每次在除了最后一個分類列之外的任何列出現一個 “break”?(值的改變)?,則問訊會產生一個高聚集累計行。
例如,在沒有?ROLLUP的情況下,一個以年、國家和產品為基礎的關于?sales?表的一覽表可能如下所示:
mysql>?SELECT?year,?country,?product,?SUM(profit)->?FROM?sales->?GROUP?BY?year,?country,?product; +------+---------+------------+-------------+ |?year?|?country?|?product????|?SUM(profit)?| +------+---------+------------+-------------+ |?2000?|?Finland?|?Computer???|????????1500?| |?2000?|?Finland?|?Phone??????|?????????100?| |?2000?|?India???|?Calculator?|?????????150?| |?2000?|?India???|?Computer???|????????1200?| |?2000?|?USA?????|?Calculator?|??????????75?| |?2000?|?USA?????|?Computer???|????????1500?| |?2001?|?Finland?|?Phone??????|??????????10?| |?2001?|?USA?????|?Calculator?|??????????50?| |?2001?|?USA?????|?Computer???|????????2700?| |?2001?|?USA?????|?TV?????????|?????????250?| +------+---------+------------+-------------+
表示總值的輸出結果僅位于年/國家/產品的分析級別。當添加了?ROLLUP后, 問詢會產生一些額外的行:
mysql>?SELECT?year,?country,?product,?SUM(profit) ????->?FROM?sales ????->?GROUP?BY?year,?country,?product?WITH?ROLLUP;+------+---------+------------+-------------+ |?year?|?country?|?product????|?SUM(profit)?| +------+---------+------------+-------------+ |?2000?|?Finland?|?Computer???|????????1500?| |?2000?|?Finland?|?Phone??????|?????????100?| |?2000?|?Finland?|?NULL???????|????????1600?| |?2000?|?India???|?Calculator?|?????????150?| |?2000?|?India???|?Computer???|????????1200?| |?2000?|?India???|?NULL???????|????????1350?| |?2000?|?USA?????|?Calculator?|??????????75?| |?2000?|?USA?????|?Computer???|????????1500?| |?2000?|?USA?????|?NULL???????|????????1575?| |?2000?|?NULL????|?NULL???????|????????4525?| |?2001?|?Finland?|?Phone??????|??????????10?| |?2001?|?Finland?|?NULL???????|??????????10?| |?2001?|?USA?????|?Calculator?|??????????50?| |?2001?|?USA?????|?Computer???|????????2700?| |?2001?|?USA?????|?TV?????????|?????????250?| |?2001?|?USA?????|?NULL???????|????????3000?| |?2001?|?NULL????|?NULL???????|????????3010?| |?NULL?|?NULL????|?NULL???????|????????7535?| +------+---------+------------+-------------+
對于這個問詢, 添加ROLLUP?子句使村輸出結果包含了四層分析的簡略信息,而不只是一個下面是怎樣解釋? ROLLUP輸出:
-
一組給定的年份和國家的每組產品行后面,?會產生一個額外的總計行, 顯示所有產品的總值。這些行將產品列設置為?NULL。
-
一組給定年份的行后面,會產生一個額外的總計行,顯示所有國家和產品的總值。這些行將國家和產品列設置為? NULL。
-
最后,?在所有其它行后面,會產生一個額外的總計列,顯示所有年份、國家及產品的總值。 這一行將年份、國家和產品列設置為?NULL。
使用ROLLUP?時的其它注意事項
以下各項列出了一些MySQL執行ROLLUP的特殊狀態:
當你使用?ROLLUP時,?你不能同時使用?ORDER BY子句進行結果排序。換言之,?ROLLUP?和ORDER BY?是互相排斥的。然而,你仍可以對排序進行一些控制。在?MySQL中,?GROUP BY?可以對結果進行排序,而且你可以在GROUP BY列表指定的列中使用明確的?ASC和DESC關鍵詞,從而對個別列進行排序。?(不論如何排序被ROLLUP添加的較高級別的總計行仍出現在它們被計算出的行后面)。
LIMIT可用來限制返回客戶端的行數。LIMIT?用在?ROLLUP后面,?因此這個限制 會取消被ROLLUP添加的行。例如:
mysql>?SELECT?year,?country,?product,?SUM(profit) ????->?FROM?sales ????->?GROUP?BY?year,?country,?product?WITH?ROLLUP ????->?LIMIT?5;+------+---------+------------+-------------+ |?year?|?country?|?product????|?SUM(profit)?| +------+---------+------------+-------------+ |?2000?|?Finland?|?Computer???|????????1500?| |?2000?|?Finland?|?Phone??????|?????????100?| |?2000?|?Finland?|?NULL???????|????????1600?| |?2000?|?India???|?Calculator?|?????????150?| |?2000?|?India???|?Computer???|????????1200?| +------+---------+------------+-------------+
將ROLLUP同?LIMIT一起使用可能會產生更加難以解釋的結果,原因是對于理解高聚集行,你所掌握的上下文較少。
在每個高聚集行中的NULL?指示符會在該行被送至客戶端時產生。服務器會查看最左邊的改變值后面的GROUP BY子句指定的列。對于任何結果集合中的,有一個詞匹配這些名字的列,?其值被設為?NULL。(若你使用列數字指定了分組列,則服務器會通過數字確定將哪個列設置為?NULL)。
由于在高聚集行中的?NULL值在問詢處理階段被放入結果集合中,你無法將它們在問詢本身中作為NULL值檢驗。例如,你無法將?HAVING product IS NULL?添加到問詢中,從而在輸出結果中刪去除了高聚集行以外的部分。
另一方面, NULL值在客戶端不以?NULL?的形式出現, 因而可以使用任何MySQL客戶端編程接口進行檢驗。
3.?具有隱含字段的GROUP BY
MySQL?擴展了?GROUP BY的用途,因此你可以使用SELECT?列表中不出現在GROUP BY語句中的列或運算。這代表 “對該組的任何可能值 ”。你可以通過避免排序和對不必要項分組的辦法得到它更好的性能。例如,在下列問詢中,你無須對customer.name?進行分組:
mysql>?SELECT?order.custid,?customer.name,?MAX(payments) ????->?FROM?order,customer ????->?WHERE?order.custid?=?customer.custid ????->?GROUP?BY?order.custid;
在標準SQL中,?你必須將?customer.name添加到?GROUP BY子句中。在MySQL中,?假如你不在ANSI模式中運行,則這個名字就是多余的。
假如你從?GROUP BY?部分省略的列在該組中不是唯一的,那么不要使用這個功能!?你會得到非預測性結果。
在有些情況下,你可以使用MIN()和MAX()?獲取一個特殊的列值,即使他不是唯一的。下面給出了來自包含排序列中最小值的列中的值:
SUBSTR(MIN(CONCAT(RPAD(sort,6,’ ‘),column)),7)
注意,假如你正在嘗試遵循標準?SQL,?你不能使用GROUP BY或?ORDER BY子句中的表達式。你可以通過使用表達式的別名繞過這一限制:
mysql>?SELECT?id,FLOOR(value/100)?AS?val ????->?FROM?tbl_name ????->?GROUP?BY?id,?val?ORDER?BY?val;
然而, MySQL允許你使用GROUP BY?及?ORDER BY?子句中的表達式。例如:
mysql>?SELECT?id,?FLOOR(value/100)?FROM?tbl_name?ORDER?BY?RAND();
?以上就是MySQL基礎教程13 —— 函數之與GROUP BY子句同時使用的函數的內容,更多相關內容請關注PHP中文網(www.php.cn)!