前一篇學過 GROUP BY 可以把資料分組並壓縮。
但光是分組,能做的事情有限。
GROUP BY 真正強大的地方,是搭配聚合函數一起使用。
比如說,老闆問你:「每個客人的平均消費金額是多少?」
這時候你需要先把訂單按照客人分組,再對每一組計算平均金額。
這就是 GROUP BY 搭配聚合函數的威力。
範例:計算每個客人的平均消費金額
老闆說:「我想知道每個客人的平均訂單金額,這樣我才知道他們的消費能力。」
假設我們有一張訂單表:
| 訂單編號 | 會員 | 金額 |
|---|---|---|
| 1 | Alice | 100 |
| 2 | Alice | 200 |
| 3 | Bob | 3000 |
| 4 | Alice | 300 |
| 5 | Bob | 3000 |
這時候你需要:
- 把訂單按照會員分組
- 對每一組計算金額的平均
SELECT 會員, AVG(金額)
FROM 訂單
GROUP BY 會員執行過程
第一步:FROM 訂單
先找到訂單表,拿到全部 5 筆資料。
第二步:GROUP BY 會員
把「會員欄位值相同的」放在一起:
| 組別 | 訂單編號 | 會員 | 金額 |
|---|---|---|---|
| 第一組 | 1 | Alice | 100 |
| 第一組 | 2 | Alice | 200 |
| 第一組 | 4 | Alice | 300 |
| 第二組 | 3 | Bob | 3000 |
| 第二組 | 5 | Bob | 3000 |
Alice 有 3 筆訂單,變成一組。
Bob 有 2 筆訂單,變成一組。
然後把每一組壓縮成一列。
這裡有個重點:GROUP BY 在壓縮的時候,會「暫時保留」其他欄位的資料,讓聚合函數可以計算。
壓縮後,表面上只剩會員欄位:
| 會員 |
|---|
| Alice |
| Bob |
但資料庫背後還記得每一組有哪些資料:
- Alice 那一組:訂單編號 1、2、4,金額 100、200、300
- Bob 那一組:訂單編號 3、5,金額 3000、3000
前一篇說「壓縮後其他欄位會消失」,其實不完全正確。
這些欄位沒有真的消失,只是你沒辦法直接 SELECT 它們,必須透過聚合函數來使用。
為什麼?
因為 Alice 那一組有 3 個金額(100、200、300),如果你直接 SELECT 金額,資料庫不知道要輸出哪一個。
但如果你用 AVG(金額),資料庫就知道要把這 3 個金額加起來算平均,輸出一個明確的數字。
第三步:SELECT 會員, AVG(金額)
SELECT 會員, AVG(金額) 告訴資料庫:我要會員欄位,還有每一組金額的平均。
這時候資料庫會用 GROUP BY 暫時保留的金額資料,計算每一組的聚合結果:
- 第一組:會員是 Alice,金額有 100、200、300,平均是 (100 + 200 + 300) / 3 = 200
- 第二組:會員是 Bob,金額有 3000、3000,平均是 (3000 + 3000) / 2 = 3000
最後輸出:
| 會員 | AVG(金額) |
|---|---|
| Alice | 200 |
| Bob | 3000 |
這樣就知道 Alice 的平均客單價是 200 元,Bob 的平均客單價是 3000 元。
規則:SELECT 欄位的限制
前面的範例解釋了為什麼聚合函數可以出現在 SELECT。
這裡整理成規則:
如果你用了 GROUP BY,SELECT 裡面的欄位必須符合以下其中一個條件:
- 出現在 GROUP BY 裡面
- 放在聚合函數裡面
以這個範例來說:
SELECT 會員, AVG(金額)
FROM 訂單
GROUP BY 會員會員可以出現在 SELECT,因為它在 GROUP BY 裡面AVG(金額)可以出現在 SELECT,因為金額放在聚合函數裡面
但如果你這樣寫:
SELECT 會員, 金額
FROM 訂單
GROUP BY 會員資料庫會報錯,因為金額既不在 GROUP BY 裡面,也沒有放在聚合函數裡面。
常用的聚合函數:
| 函數 | 用途 |
|---|---|
| COUNT() | 計算數量 |
| SUM() | 加總 |
| AVG() | 平均 |
| MAX() | 最大值 |
| MIN() | 最小值 |
練習:常見的統計需求
老闆常問的問題,通常都是 GROUP BY 加聚合函數的組合。
關鍵是找出兩件事:
- 按照什麼分組? → 這是 GROUP BY 的欄位
- 要算什麼? → 這是聚合函數的運算
練習一:每個年齡層有多少會員?
老闆說:「請告訴我會員在每個年紀的數量分佈。」
分析:
- 按照什麼分組?年紀
- 要算什麼?數量(COUNT)
SELECT 年紀, COUNT(會員)
FROM 會員
GROUP BY 年紀練習二:每個小組的最高銷售額是多少?
老闆說:「請告訴我每個業務小組的銷售額最高是多少。」
分析:
- 按照什麼分組?小組
- 要算什麼?最大值(MAX)
SELECT 小組, MAX(銷售額)
FROM 業績表
GROUP BY 小組練習三:每天加入的會員有多少人?
老闆說:「請告訴我每天加入的會員分別有多少人。」
分析:
- 按照什麼分組?加入日期
- 要算什麼?數量(COUNT)
SELECT 加入日期, COUNT(會員)
FROM 會員
GROUP BY 加入日期GROUP BY 與資料視覺化
你有沒有發現,GROUP BY 加聚合函數的結果,很像在畫圖表?
以「每天加入的會員數量」為例:
| 加入日期 | COUNT(會員) |
|---|---|
| 2024-01-01 | 5 |
| 2024-01-02 | 8 |
| 2024-01-03 | 3 |
| 2024-01-04 | 12 |
| 2024-01-05 | 6 |
如果把這個結果畫成折線圖:
- X 軸是加入日期
- Y 軸是會員數量
你馬上就能看出會員加入的趨勢。
這也是為什麼 GROUP BY 加聚合函數非常常用——它就是在做統計和視覺化的前置作業。
加上 ORDER BY 排序後,趨勢會更明顯:
SELECT 加入日期, COUNT(會員)
FROM 會員
GROUP BY 加入日期
ORDER BY 加入日期這樣日期會按照順序排列,看起來就像一張時間序列圖表。
小結
這篇文章介紹了 GROUP BY 搭配聚合函數:
- 為什麼要搭配聚合函數:聚合函數可以把「多筆資料」變成「一個數字」,讓壓縮後的欄位有值可以輸出
- SELECT 欄位的規則:欄位必須出現在 GROUP BY 裡,或是放在聚合函數裡
- 常見的統計需求:找出「按照什麼分組」和「要算什麼」,就能寫出正確的 SQL
- 與資料視覺化的關係:GROUP BY 加聚合函數的結果,很適合拿來畫圖表
下一篇會學習如何在分組之後再做篩選,也就是 HAVING 子句。