萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL WHERE vs HAVING:一圖看懂過濾時機與適用場景

核心區別:執行順序不同

SQL 執行邏輯順序:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT

  • WHERE:分組前過濾原始行,不可使用聚合函數。
  • HAVING:分組後過濾聚合結果,可使用聚合函數/別名。

直觀示例

場景一:無聚合,結果相同但語義不同

SELECT * FROM welcome WHERE id > 1;      -- 行級過濾
SELECT * FROM welcome HAVING id > 1;     -- 把全表當一組,組級過濾(MySQL 允許,但不推薦)

場景二:有聚合,WHERE 報錯,HAVING 正常

-- 錯誤:WHERE 不能用聚合函數
SELECT user, MAX(salary) FROM users GROUP BY user WHERE MAX(salary) > 10;
-- ERROR 1111 (HY000): Invalid use of group function

-- 正確:HAVING 過濾聚合後結果
SELECT user, MAX(salary) FROM users GROUP BY user HAVING MAX(salary) > 10;

何時用 WHERE?何時用 HAVING?

場景推薦子句理由
過濾原始列(如 status=1, age>18)WHERE利用索引,早期過濾減少參與分組的行數,性能最優
過濾聚合結果(如 COUNT(*)>5, SUM(amount)>1000)HAVING聚合函數只能在 HAVING/SELECT/ORDER BY 中使用
同時存在WHERE + HAVINGWHERE 先篩選行 → GROUP BY → HAVING 再篩選組

組合使用最佳實踐

-- 需求:查詢 2023 年下單金額超過 10000 元的用戶
SELECT user_id, SUM(amount) AS total
FROM orders
WHERE YEAR(create_time) = 2023        -- ① 先按年份過濾行(可用索引)
GROUP BY user_id
HAVING SUM(amount) > 10000;           -- ② 再按聚合金額過濾組

常見誤區

  1. 以為 HAVING 只能配合 GROUP BY:MySQL 允許無 GROUP BY 時用 HAVING(視全表為一組),但語義怪異,建議統一用 WHERE。
  2. 在 HAVING 中用別名:MySQL 支持 HAVING total > 10000(別名),標準 SQL 不一定支持,移植性考慮寫全稱 HAVING SUM(amount) > 10000。
  3. 把非聚合列放入 HAVING:如 HAVING name='abc',雖 MySQL 允許但邏輯混淆,應移至 WHERE。

總結

WHERE 過濾行,HAVING 過濾組。 能用 WHERE 解決的絕不拖到 HAVING,這不僅是語法規範,更是性能鐵律——越早過濾,掃描行數越少,查詢越快。

copyright © 萬盛學電腦網 all rights reserved