GROUP BY 子句通常與彙總函式一起使用,按照一列或多列的值對查詢結果中的資料行分組,為每個不同的組合產生一個合計列。除顯式指定分組鍵外,還可以使用 GROUP BY ALL 根據 SELECT 列表自動確定分組鍵,或搭配 ROLLUP、CUBE 和 GROUPING SETS 子句擴充分組功能。
基本文法
可根據分析情境選擇以下分組寫法,其中 ROLLUP、CUBE、GROUPING SETS 在 GROUP BY 基礎上擴充分組功能:
分析情境 | 適用寫法 |
按顯式指定的列或運算式對分析結果分組(最常用) |
|
分組鍵較多或需要調整分析維度,由 |
|
為每個分組返回一個小計,為所有分組返回一個總計 |
|
按照所有可能的列組合分組 |
|
按照指定的多個分組集合分別分組 |
|
在 SQL 陳述式中,普通分組查詢的 SELECT 列表只能包含以下內容:
GROUP BY子句中指定的列或運算式對任意列的彙總計算結果,如
COUNT()、SUM()等使用
GROUP BY ALL時,分組鍵由SELECT列表自動推導,無需在GROUP BY子句中重複列出。還可以在分組結果上使用視窗函數,參見樣本 9。
直接選擇非 GROUP BY 列是不允許的,因為這些列的值在分組後可能不唯一,無法明確其含義。例如,以下語句是非法的:
* | SELECT status, request_time, COUNT(*) AS PV GROUP BY status原因是 request_time 並未包含在 GROUP BY 子句中,也未彙總。正確的寫法可以是:
* | SELECT status, arbitrary(request_time), COUNT(*) AS PV GROUP BY statusarbitrary(request_time) 是對 request_time 彙總的一種方式,表示從每個分組中任意選取一個 request_time 值,既符合 SQL 文法規則,又能滿足查詢需求。
GROUP BY
對分析結果分組。
SELECT
key1,
...,
aggregate_function
GROUP BY key,...參數說明:
key1:分組鍵,即用於分組的列,支援按日誌欄位名稱或彙總函式計算結果列分組。GROUP BY子句支援單列或多列。aggregate_function:應用在每個分組上的彙總函式,如count、min、max、avg和sum等。
完整樣本參見樣本 1~樣本 3。
GROUP BY ALL
GROUP BY ALL 自動將 SELECT 列表中不包含彙總函式、也不包含視窗函數的運算式作為分組鍵,無需在 GROUP BY 子句中重複列出這些運算式。適合分組鍵較多,或需要調整分析維度情境。
SELECT
key1,
key2,
aggregate_function
GROUP BY ALL參數說明:
key1、key2:分組鍵,可以是欄位或運算式,例如status、request_method、substr(request_method, 1, 1)或CASE運算式。運算式按其完整計算結果分組;GROUP BY ALL後不跟任何欄位或別名,SELECT列表中已設定的別名無需重複引用。aggregate_function:應用在每個分組上的彙總函式,例如count(*)、sum(request_time)和avg(request_time)。
例如,以下兩條語句等價:
* | SELECT request_method, status, count(*) AS PV GROUP BY ALL* | SELECT request_method, status, count(*) AS PV GROUP BY request_method, statusSELECT 列表的通用合法性規則參見本章開頭的重要提示,GROUP BY ALL 的使用規則和限制如下:
自動分組以當前
SELECT列表為準,不會按日誌中的全部欄位分組。增加或刪除非彙總、非視窗運算式會相應改變分組維度。不支援在同一層查詢中將
GROUP BY ALL與SELECT *、SELECT 表別名.*或SELECT *, count(*)組合使用,請顯式列出欄位。該限制針對SELECT *這類通配選擇,顯式列出欄位後使用count(*)等彙總函式不受影響。包含彙總函式或視窗函數的整個運算式不會被自動加入分組鍵,例如
sum(request_time) / count(*)整體不參與分組。如果此類運算式之外還直接選擇了未彙總的欄位(例如未經arbitrary()等彙總函式處理的request_time),仍須滿足普通GROUP BY的分組規則。當
SELECT列表只有彙總運算式時,對全部符合查詢條件的資料全域彙總。例如* | SELECT count(*) AS PV, sum(request_time) AS total_time GROUP BY ALL與省略GROUP BY ALL的寫法等價。支援與
WHERE、HAVING、ORDER BY以及視窗函數配合使用。視窗函數基於分組彙總後的結果計算,其引用的欄位仍需滿足分組規則。只有單獨書寫的
GROUP BY ALL才會自動推導分組鍵,GROUP BY ALL status或GROUP BY ALL ROLLUP (...)中的ALL不會觸發自動推導。需要按名為
all的欄位或別名分組時,請使用雙引號,例如GROUP BY "all"。預設情況下,即使存在名為all的欄位,單獨的GROUP BY ALL仍會自動推導分組鍵。
完整樣本參見樣本 7~樣本 9。
GROUP BY ROLLUP
GROUP BY ROLLUP 子句按匯總層級分組,為每個分組返回一個小計,為所有分組返回一個總計。例如 GROUP BY ROLLUP (a, b) 的結果集為 (a, b)、(a, null) 和 (null, null)。完整樣本參見樣本 6。
SELECT
key1,
...,
aggregate_function
GROUP BY ROLLUP (key1,...)參數說明如下所示:
key1:是您希望根據其值來分組的列,支援按照日誌欄位名稱或彙總函式計算結果列進行分組。GROUP BY子句支援單列或多列。aggregate_function:是應用在每個分組上的彙總函式,如count、min、max、avg和sum等。
GROUP BY CUBE
GROUP BY CUBE 子句按照所有可能的列組合分組。例如 GROUP BY CUBE (a, b) 的結果集為 (a, b)、(null, b)、(a, null) 和 (null, null)。完整樣本參見樣本 5。
SELECT
key1,
...,
aggregate_function
GROUP BY CUBE (key1,...)參數說明如下所示:
key1:是您希望根據其值來分組的列,支援按照日誌欄位名稱或彙總函式計算結果列進行分組。GROUP BY子句支援單列或多列。aggregate_function:是應用在每個分組上的彙總函式,如count、min、max、avg和sum等。
GROUP BY GROUPING SETS
GROUP BY GROUPING SETS 子句按照指定的多個分組集合分別分組,未參與某個分組集合的列在該集合的結果中為 null。例如 GROUP BY GROUPING SETS (a, b) 的結果集為 (a, null) 和 (null, b)。完整樣本參見樣本 4。
SELECT
key1,
...,
aggregate_function
GROUP BY GROUPING SETS (key1,...)參數說明如下所示:
key1:是您希望根據其值來分組的列,支援按照日誌欄位名稱或彙總函式計算結果列進行分組。GROUP BY子句支援單列或多列。aggregate_function:是應用在每個分組上的彙總函式,如count、min、max、avg和sum等。
樣本
樣本 1:按狀態代碼統計請求次數
統計不同狀態代碼對應的請求次數。
查詢和分析語句
* | SELECT status, count(*) AS PV GROUP BY status查詢和分析結果以表格形式展示,包含 status 和 PV 兩列,分別顯示各 HTTP 狀態代碼及其對應的頁面訪問量統計值。
樣本 2:按小時統計網站訪問 PV
按照每小時的時間粒紋計算網站訪問 PV。
查詢和分析語句
__time__欄位為Log Service中的保留欄位,表示時間列;time為date_trunc('hour', __time__)的別名,函數用法參見 date_trunc 函數。
* |
SELECT
count(*) AS PV,
date_trunc('hour', __time__) AS time
GROUP BY
time
ORDER BY
time
LIMIT
1000查詢和分析結果:返回包含 PV 和 time 兩列的結果,樣本資料:PV 分別為 1202、10159、28001,對應時間為 2021-08-10 00:00:00.000、2021-08-10 01:00:00.000、2021-08-10 02:00:00.000。
樣本 3:按 5 分鐘時間粒紋統計 PV
按照每 5 分鐘的時間粒紋計算 PV。
查詢和分析語句
由於 date_trunc 函數只能按照固定時間間隔統計,需要按照自訂時間統計分析時,請按照數學模數方法分組。例如 %300 表示按照 5 分鐘的時間粒紋模數對齊。
* |
SELECT
count(*) AS PV,
__time__-__time__ % 300 AS time
GROUP BY
time
LIMIT
1000查詢和分析結果返回三條記錄:PV=143 對應 time=1628525100,PV=31 對應 time=1628526600,PV=44 對應 time=1628526900。
樣本 4:按指定分組集合統計訪問資料 (GROUPING SETS)
根據要求方法和請求狀態分組,先計算各個要求方法對應的訪問資料,再計算各個請求狀態對應的訪問數量。
查詢和分析語句
* |
SELECT
request_method,
status,
count(*) AS PV
GROUP BY
GROUPING SETS (request_method, status)查詢和分析結果:按
request_method分組時,status為 null,各方法 PV 值分別為:GET=285、POST=51、DELETE=28、PUT=60;按status分組時,request_method為 null,各狀態代碼 PV 值分別為:200=382、204=2、501=2、202=4、305=4。
樣本 5:按所有列組合統計訪問資料 (CUBE)
根據要求方法和請求狀態分組,分組集包括 (null, null)、(request_method, null)、(null, status) 和 (request_method, status),計算以上各個分組的訪問數量。
查詢和分析語句
* |
SELECT
request_method,
status,
count(*) AS PV
GROUP BY
CUBE (request_method, status)查詢和分析結果:查詢結果包含 request_method、status、PV 三列,共 43 條記錄。CUBE 分組產生的彙總行中,
request_method或status為 null 表示該維度小計。例如:null/null 的 PV 為 285(總計),GET/null 為 189,POST/null 為 47,PUT/null 為 39,DELETE/null 為 9,HEAD/null 為 1;null/200 為 259,null/201 為 2,null/202 為 2。
樣本 6:按匯總層級統計小計與總計 (ROLLUP)
根據要求方法和請求狀態分組,分組集包括 (request_method, status)、(request_method, null) 和 (null, null),計算以上各個分組的訪問數量。
查詢和分析語句
* |
SELECT
request_method,
status,
count(*) AS PV
GROUP BY
ROLLUP (request_method, status)查詢和分析結果:查詢結果包含 request_method、status、PV 三列,共 33 條記錄。ROLLUP 函數在各分組層級產生合計列,其中
null表示該列已被彙總:例如GET / null / 162表示 GET 方法所有狀態代碼的合計 PV 為 162,null / null / 285表示所有方法與狀態代碼的總計 PV 為 285。
樣本 7:自動按多個欄位分組 (GROUP BY ALL)
根據要求方法和狀態代碼統計請求次數,只保留請求次數大於 100 的分組。
查詢和分析語句
* |
SELECT
request_method,
status,
count(*) AS PV
GROUP BY ALL
HAVING count(*) > 100
ORDER BY PV DESC查詢和分析結果:包含 request_method、status 和 PV 三列,僅返回請求次數大於 100 的組合,並按 PV 從高到低排列。分組方式等價於
GROUP BY request_method, status。
樣本 8:自動按運算式分組 (GROUP BY ALL)
按照每 5 分鐘的時間粒紋和要求方法統計 PV,無需重複填寫時間運算式或其別名。
查詢和分析語句
* |
SELECT
__time__ - __time__ % 300 AS time,
request_method,
count(*) AS PV
GROUP BY ALL
ORDER BY time, request_method
LIMIT 1000查詢和分析結果:包含 time、request_method 和 PV 三列。分組方式等價於
GROUP BY __time__ - __time__ % 300, request_method。
樣本 9:對分組結果計算排名 (GROUP BY ALL)
統計各狀態代碼的請求次數,再按照請求次數從高到低計算排名。
查詢和分析語句
* |
SELECT
status,
count(*) AS PV,
rank() OVER (ORDER BY count(*) DESC) AS ranking
GROUP BY ALL
ORDER BY ranking, status查詢和分析結果:包含 status、PV 和 ranking 三列。僅
status作為分組鍵,count(*)用於彙總,rank()對彙總結果排名,不參與分組;請求次數相同的狀態代碼具有相同排名。