having子句和where有什么区别_mysql语法差异说明

11次阅读

WHERE过滤行、HAVING过滤分组结果:WHERE在GROUP BY前执行,作用于原始行且不可用聚合函数;HAVING在GROUP BY后执行,作用于分组结果且必须依赖聚合或分组字段。

having子句和where有什么区别_mysql语法差异说明

WHERE 过滤行,HAVING 过滤分组结果

这是最本质的区别:WHERE 在 GROUP BY 之前执行,作用对象是原始数据的每一行;HAVING 在 GROUP BY 之后执行,作用对象是已经分组并计算完聚合函数(如 count()SUM())的结果集。

  • WHERE COUNT(*) > 10 会报错 —— 因为 COUNT(*) 还没算出来,行都还没分组
  • HAVING COUNT(*) > 10 是合法的 —— 分组完成,每组一个计数,可以筛掉人数 ≤10 的组
  • WHERE 排除的行,不参与后续分组;HAVING 排除的是整组,不影响其他组

WHERE 不能用聚合函数,HAVING 必须依赖聚合或分组字段

你不能在 WHERE 中写 WHERE AVG(salary) > 8000mysql 会直接拒绝解析。而 HAVING 不仅允许,而且通常就靠它来实现“哪些部门平均工资超 8k”这类需求。

  • 正确示例:
    SELECT dept, AVG(salary) AS avg_sal FROM emp GROUP BY dept HAVING avg_sal > 8000;
  • 错误写法:
    SELECT dept, AVG(salary) AS avg_sal FROM emp WHERE avg_sal > 8000 GROUP BY dept;

    avg_sal 是别名,且出现在 WHERE 中,双重非法)

  • HAVING 可以用别名(如 avg_sal),WHERE 不行 —— 因为 select 列别名在 WHERE 阶段还不可见

性能差异:WHERE 能走索引,HAVING 基本不走

如果过滤条件字段上有索引,放在 WHERE 中大概率能命中索引,大幅减少扫描行数;而 HAVING 是对内存中已分组的结果再筛,无法利用底层表索引。

  • 想查 “2024 年入职且部门平均薪资 > 15k 的部门”,应把 WHERE hire_date >= '2024-01-01' 放前面,先缩小数据集
  • 若错误地写成 HAVING hire_date >= '2024-01-01',不仅语法错(hire_date 未在 GROUP BY 中也不聚合),更关键的是:即使能运行,也会全表扫完再分组,再筛 —— 白耗资源
  • 关联查询中,WHERE 先筛再 join,HAVING 是 join 后再筛,前者效率通常高得多

执行顺序决定能否混用 —— 不是“选一个”,而是“各司其职”

标准 MySQL 查询执行顺序是:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT。这意味着你经常需要 WHERE 和 HAVING 同时出现,各自干好自己的活。

  • 典型组合场景:
    SELECT dept, COUNT(*) AS cnt, AVG(salary) FROM emp  WHERE status = 'active' AND salary > 3000  GROUP BY dept  HAVING cnt >= 5 AND AVG(salary) > 12000  ORDER BY cnt DESC;
  • 这里:WHERE 确保只统计在职且底薪够高的员工(影响分组基数);HAVING 确保只返回人数 ≥5 且平均薪资 >1.2w 的部门(影响最终输出行数)
  • 漏掉 WHERE 可能导致无效数据进分组;漏掉 HAVING 可能返回大量无业务意义的分组结果

真正容易被忽略的点是:**HAVING 不是 WHERE 的“升级版”,它是 GROUP BY 的配套子句**。没有 GROUP BY 却写 HAVING,虽然某些 MySQL 版本允许(视为对整个结果集做一次隐式分组),但语义模糊、可读性差、迁移风险高 —— 生产环境应避免。

text=ZqhQzanResources