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客戶端編程接口進行檢驗。