☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
sql 初學

GROUP BY 與 HAVING 分組統計

GROUP BY — 分組統計

比喻:GROUP BY 就像把學生按班級分組 📦

全校 300 個學生,你想知道「每班平均分數」—— 先把學生按班級分組,再對每組算平均。 這就是 GROUP BY 的概念。


基本用法

-- 每個科系有幾個學生?
SELECT Department,            -- ← 分組的欄位
       COUNT(*) AS 學生人數    -- ← 每組的統計
FROM Students
GROUP BY Department;          -- ← 按 Department 分組

逐行解析:

SELECT Department        -- 顯示科系名稱
       COUNT(*) AS 學生人數  -- 每組有幾筆 = 每系幾人
FROM Students            -- 從學生表
GROUP BY Department      -- 把相同 Department 的資料歸為一組
                         -- 結果是:每組一列

結果:

 Department | 學生人數
-----------+---------
 資工系     |      15
 電機系     |      12
 企管系     |      20

搭配聚合函數

-- 每個科系的平均分數、最高分、最低分
SELECT
    Department AS 科系,
    COUNT(*) AS 人數,
    ROUND(AVG(Score), 1) AS 平均分,
    MAX(Score) AS 最高分,
    MIN(Score) AS 最低分
FROM Students
GROUP BY Department
ORDER BY 平均分 DESC;        -- ← 按平均分排序(高到低)

⚠️ GROUP BY 的重要規則

-- ❌ 錯誤:SELECT 裡的非聚合欄位,必須出現在 GROUP BY 裡
SELECT Department, Name, COUNT(*)
FROM Students
GROUP BY Department;
-- 錯誤!Name 不在 GROUP BY 裡,資料庫不知道要顯示哪個 Name

-- ✅ 正確:
SELECT Department, COUNT(*)
FROM Students
GROUP BY Department;

-- ✅ 或者把 Name 也加入 GROUP BY
SELECT Department, Name, COUNT(*)
FROM Students
GROUP BY Department, Name;   -- 變成「每系 + 每人」一組

多欄分組

-- 按科系和性別分組
SELECT
    Department AS 科系,
    Gender AS 性別,
    COUNT(*) AS 人數,
    AVG(Score) AS 平均分
FROM Students
GROUP BY Department, Gender  -- ← 兩個欄位一起分組
ORDER BY Department, Gender;

結果:

 科系   | 性別 | 人數 | 平均分
-------+------+------+-------
 資工系 | 男   |   10 | 78.5
 資工系 | 女   |    5 | 82.3
 電機系 | 男   |    8 | 75.0
 電機系 | 女   |    4 | 80.1

HAVING — 過濾分組結果

WHERE 是在分組過濾(過濾個別資料列) HAVING 是在分組過濾(過濾分組結果)

-- 只顯示人數超過 10 的科系
SELECT Department, COUNT(*) AS 人數
FROM Students
GROUP BY Department
HAVING COUNT(*) > 10;        -- ← 只要人數 > 10 的組

逐行解析:

GROUP BY Department      -- 先分組
HAVING COUNT(*) > 10     -- 分完組之後,過濾掉人數 <= 10 的組
                         -- HAVING 裡只能用聚合函數或 GROUP BY 的欄位

WHERE vs HAVING

-- 找出「分數 >= 60 的學生中」每系平均超過 80 的科系
SELECT Department, AVG(Score) AS 平均分
FROM Students
WHERE Score >= 60            -- ① 先過濾:只看及格的學生
GROUP BY Department          -- ② 再分組:按科系
HAVING AVG(Score) > 80       -- ③ 最後過濾組:只要平均 > 80
ORDER BY 平均分 DESC;        -- ④ 排序結果

SQL 執行順序

1. FROM      — 從哪個表
2. WHERE     — 過濾個別列
3. GROUP BY  — 分組
4. HAVING    — 過濾分組
5. SELECT    — 選欄位
6. ORDER BY  — 排序
7. LIMIT     — 取前 N 筆

💡 這個順序很重要!它解釋了為什麼 WHERE 不能用聚合函數——因為 WHERE 在 GROUP BY 之前執行,那時候還沒分組呢。


實用範例

-- 找出購買次數最多的前 5 個客戶
SELECT CustomerId, COUNT(*) AS 購買次數, SUM(Amount) AS 消費總額
FROM Orders
GROUP BY CustomerId
ORDER BY 購買次數 DESC
LIMIT 5;

-- 找出每月營業額超過 10 萬的月份
SELECT
    DATE_TRUNC('month', OrderDate) AS 月份,
    SUM(Amount) AS 月營業額
FROM Orders
GROUP BY DATE_TRUNC('month', OrderDate)
HAVING SUM(Amount) > 100000
ORDER BY 月份;

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊