三者是 SQL 查詢的核心子句,但語義、執行順序、搭配規則常被混淆。本文從定義、標準語法順序、聚合函數依賴、WHERE vs HAVING 差異四個維度徹底釐清。
| 子句 | 核心語義 | 必需條件 | 典型搭配 |
|---|---|---|---|
ORDER BY | 結果集行排序 | 指定排序列 | ASC/DESC、多級排序 |
GROUP BY | 數據分組聚合 | 至少一個分組列 + 聚合函數 | SUM/COUNT/AVG/MIN/MAX |
HAVING | 分組後過濾 | 條件含聚合函數 | 配合 GROUP BY 使用 |
SELECT select_list
FROM table_source
WHERE search_condition -- 1. 行級過濾(無聚合)
GROUP BY group_by_expression -- 2. 分組
HAVING search_condition -- 3. 組級過濾(可含聚合)
ORDER BY order_list -- 4. 最終排序
記憶口訣: Where → Group → Having → Order(先過濾行,再分組,再過濾組,最後排序)。
錯誤示例:
SELECT A, B FROM t GROUP BY A; -- B 未聚合且未在 GROUP BY,報錯
正確寫法:
SELECT A, COUNT(B) AS cnt FROM t GROUP BY A; -- B 經聚合
-- 或
SELECT A, B FROM t GROUP BY A, B; -- B 納入分組鍵
| 維度 | WHERE | HAVING |
|---|---|---|
| 執行階段 | GROUP BY 之前 | GROUP BY 之後 |
| 可用列 | 表原始列 | SELECT 列表中的列/別名 + 聚合函數 |
| 聚合函數 | 不可用 | 可用(常用) |
| 典型場景 | 業務條件過濾 | 聚合指標篩選 |
需求:統計各部門薪資總和 > 50萬 的部門,按總薪資降序。
SELECT dept_name, SUM(salary) AS total_salary, COUNT(*) AS emp_cnt
FROM employees
WHERE status = '在職' -- 1. 先過濾在職員工
GROUP BY dept_name -- 2. 按部門分組
HAVING SUM(salary) > 500000 -- 3. 過濾薪資總和>50萬的組
ORDER BY total_salary DESC; -- 4. 最後排序
HAVING dept_name='銷售部' 應改為 WHERE dept_name='銷售部',減少分組運算量。ORDER BY 2)易因 SELECT 列變動出錯。理清三者語義邊界與執行順序,寫出的 SQL 既正確又高效。