where在分组前执行,过滤原始行;having在group by后执行,过滤分组后的聚合结果;二者执行阶段不同、不可互换,如“订单数>5的用户”必须用having count(*)>5,where中使用聚合函数会报错。

HAVING 必须跟在 GROUP BY 之后,且只能引用 SELECT 列、GROUP BY 字段或聚合函数——写错位置或引用不存在的字段,直接报错或返回空结果。
WHERE 和 HAVING 混用时谁先执行?
WHERE 在分组前过滤原始行,HAVING 在分组后过滤聚合结果。比如想查“订单数 > 5 的用户”,WHERE COUNT(*) > 5 语法错误,必须用 HAVING COUNT(*) > 5。
-
WHERE可用原始表字段(如status、created_at),不能用AVG(price)或别名avg_price -
HAVING不能用未出现在SELECT或GROUP BY中的原始字段(如HAVING user_name = 'alice'会报Unknown column 'user_name' in 'having clause') - 典型组合:先
WHERE status = 'paid'减少分组数据量,再GROUP BY user_id,最后HAVING COUNT(*) >= 3
ThinkPHP6 中 having() 方法的参数怎么写?
having() 接收字符串或数组,但字符串形式最常用,且必须是合法 SQL 表达式。注意:它不自动加反引号,字段名和函数名大小写需与数据库一致(MySQL 默认不区分,但 PostgreSQL 严格区分)。
- 正确写法:
->having('COUNT(*) > 1')、->having('AVG(score) >= 85')、->having('MAX(created_at) > ?', $date)(支持参数绑定) - 错误写法:
->having('score > 80')(score不是聚合字段,也未在GROUP BY中) - 别名不能直接用:
->field('AVG(score) AS avg_score')后,->having('avg_score > 85')在 MySQL 可能侥幸通过,但标准 SQL 不允许——应改用->having('AVG(score) > 85')
为什么 having 筛选后数据变少了,甚至为空?
常见原因不是逻辑写错,而是分组字段不全或聚合字段计算出 NULL 导致条件不匹配。
- MySQL 5.7+ 默认开启
ONLY_FULL_GROUP_BY:如果SELECT包含非聚合字段(如name)但没写进GROUP BY,查询直接失败,having根本不会执行 -
COUNT(col)忽略col为 NULL 的行,COUNT(*)统计所有分组行;若字段大量为 NULL,HAVING COUNT(email) > 1可能永远不成立 - 浮点精度问题:
HAVING AVG(price) > 99.99可能因小数位截断失效,建议用ROUND(AVG(price), 2) > 99.99或改用范围比较 - 没开调试看不到真实 SQL:加
Db::listen(function ($sql, $time, $explain) { dump($sql); });确认生成的语句是否符合预期
真正容易被忽略的是:HAVING 条件无法走索引,大数据量分组后筛选很慢;别指望靠它优化性能,该用 WHERE 过滤的,一步都不能省。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











