MySQL 允許無 GROUP BY 直接使用 HAVING,但行為與標準 SQL 不同:MySQL 內部重寫為 GROUP BY NULL,等價於 LIMIT 1 取第一行,再對全表聚合值比較。這導致 MIN/MAX 看似「失效」的反直覺現象。
CREATE TABLE t2 (a INT, id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY);
INSERT INTO t2 VALUES (1,1), (1,3);
-- 有結果
SELECT * FROM t2 HAVING id = MIN(id); -- 返回 id=1
-- 無結果
SELECT * FROM t2 HAVING id = MAX(id); -- 空集
SELECT * FROM t2 HAVING id = MIN(id)
-- 重寫為
SELECT * FROM t2 GROUP BY NULL HAVING id = MIN(id)
SELECT * FROM t2 GROUP BY NULL;
-- 等價於 LIMIT 1,只返回第一行(id=1, a=10)
SELECT MAX(a), MIN(a), MAX(id), MIN(id) FROM t2 GROUP BY NULL;
-- 結果:MAX(a)=10, MIN(a)=1, MAX(id)=3, MIN(id)=1
-- 注意:聚合掃描全表,不限於 GROUP BY NULL 的那一行!
HAVING id = MIN(id) → id = 1(全表最小 id)GROUP BY NULL 產生單組,包含第一行 id=1id=1 → 返回HAVING id = MAX(id) → id = 3(全表最大 id)id=1 ≠ 3 → 過濾掉 → 空結果-- 修改數據:a=10 在 id=1, a=1 在 id=3
SELECT * FROM t2 HAVING a = MAX(a); -- 返回 id=1 (a=10)
SELECT * FROM t2 HAVING a = MIN(a); -- 空集(第一行 a=10 ≠ 全表最小 1)
SELECT MAX(a), MIN(a), MAX(id), MIN(id) FROM t2 GROUP BY a;
-- 每組聚合,MAX=MIN=組內值,結果正確
| 特性 | 標準 SQL | MySQL (無 ONLY_FULL_GROUP_BY) |
|---|---|---|
| HAVING 需 GROUP BY | 必須 | 可選(隱式 GROUP BY NULL) |
| 聚合函數作用域 | 分組內 | 無 GROUP BY 時全表 |
| SELECT 非聚合列 | 禁止 | 允許(值不確定) |
sql_mode=ONLY_FULL_GROUP_BY(MySQL 5.7+ 默認開啟),禁止此類寫法GROUP BY,語義清晰ORDER BY ... LIMIT 1 或窗口函數,勿依賴 HAVING 技巧MySQL HAVING 無 GROUP BY 時的行為是「全表聚合 + 取第一行比較」,極易產生邏輯錯誤。這是 MySQL 早期為兼容性保留的非標準行為,現代開發應嚴格模式 + 顯式 GROUP BY,避免踩坑。