SUM、COUNT、MAX、MIN、AVG 等,作用於多筆記錄,回傳單一值。FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
記憶口訣:先篩選行,再分組,再篩選組。
bbc 為例)SELECT region, SUM(population) AS total_pop, SUM(area) AS total_area
FROM bbc
GROUP BY region;
邏輯:按 region 分組 → 每組計算 SUM。
SELECT region, SUM(population) AS total_pop, SUM(area) AS total_area
FROM bbc
GROUP BY region
HAVING SUM(area) > 1000000;
關鍵:不能用 WHERE 過濾 SUM(area),因原始表無「地區總面積」這欄位;必須用 HAVING 對聚合結果過濾。
| 錯誤寫法 | 錯誤原因 | 正確寫法 |
|---|---|---|
SELECT dept, COUNT(*) FROM emp WHERE COUNT(*) > 5 GROUP BY dept | WHERE 不能用聚合函數 | SELECT dept, COUNT(*) FROM emp GROUP BY dept HAVING COUNT(*) > 5 |
SELECT dept, name FROM emp GROUP BY dept | name 非分組欄位且未聚合 | SELECT dept, GROUP_CONCAT(name) FROM emp GROUP BY dept (MySQL) 或 STRING_AGG(name, ',') (PG/SQL Server) |
SELECT dept, SUM(sal) FROM emp GROUP BY dept, name | 多加 name 導致過度分組 | 若只需按部門統計,GROUP BY dept 即可 |
SELECT dept, job, SUM(sal)
FROM emp
GROUP BY ROLLUP (dept, job); -- 產生小計與總計行
-- 寫法 1:NOT IN 子查詢(效能較差)
SELECT TOP m * FROM tablename WHERE id NOT IN (SELECT TOP n id FROM tablename);
-- 寫法 2:暫存表 + ROWCOUNT(舊版 SQL Server)
SELECT TOP m * INTO #temp FROM tablename ORDER BY col;
SET ROWCOUNT n;
SELECT * FROM #temp ORDER BY col DESC;
-- 寫法 3:巢狀 TOP(通用)
SELECT TOP n * FROM (SELECT TOP m * FROM tablename ORDER BY col) a ORDER BY col DESC;
-- 現代寫法(MySQL 8.0+ / PG / SQL Server 2012+)
SELECT * FROM tablename ORDER BY col OFFSET n ROWS FETCH NEXT m ROWS ONLY;
GROUP BY 是「縱向切分」,HAVING 是對切分後的「組」進行過濾。OFFSET ... FETCH 更標準、可讀、效能佳。