一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

如何在SQL中使用GROUP BY和HAVING过滤分组后的数据?

时间:2026-06-18 09:10:52 编辑:袖梨 来源:一聚教程网

GROUP BY 和 HAVING 必须配合使用才能过滤分组结果;单独 HAVING 会报错,因无分组则无“分组后”数据可筛;SELECT 非聚合字段必须出现在 GROUP BY 中,否则触发 ERROR 1055;HAVING 只能引用聚合函数或分组字段,不可用原始行单值字段。

GROUP BY 和 HAVING 必须一起用才能过滤分组后的结果;单独写 HAVING 会报错,因为没有分组就没有“分组后”的数据可筛。

GROUP BY 后 SELECT 字段必须合法

MySQL(及多数标准 SQL)要求:SELECT 列表里的每个非聚合字段,都得出现在 GROUP BY 子句中。否则直接报错 ERROR 1055(在严格模式下)。

  • ✅ 正确:SELECT department, COUNT(*) FROM employees GROUP BY department;
  • ❌ 错误:SELECT name, department, COUNT(*) FROM employees GROUP BY department; —— name 既没在 GROUP BY 里,也没套聚合函数,数据库不知道该取哪一行的 name
  • ⚠️ 注意:MySQL 5.7+ 默认启用 ONLY_FULL_GROUP_BY 模式,这个限制是硬性的;关掉它只是掩盖问题,不是解决问题。

HAVING 只能用聚合结果或分组字段做条件

HAVING 是对「每组聚合完之后」那行结果做判断,所以条件里可以放心用 COUNT(*)SUM(amount) 这类,但不能用原始行的单值字段(除非它也在 GROUP BY 里)。

  • ✅ 正确:HAVING COUNT(*) > 3HAVING AVG(salary) >= 12000HAVING department = 'tech'(因为 department 是分组字段)
  • ❌ 错误:HAVING salary > 10000 —— salary 不是分组字段,也不是聚合结果,这行根本不存在于 HAVING 执行时的上下文中。
  • ? 小技巧:如果想先筛高薪员工再分组,应该用 WHERE salary > 10000 放在 GROUP BY 前面,而不是硬塞进 HAVING。

WHERE 和 HAVING 的执行顺序不能颠倒

SQL 实际执行顺序是:FROM → WHERE → GROUP BY → 聚合计算 → HAVING → SELECT → ORDER BY。这个顺序决定了什么能做什么不能做。

  • WHERE 在分组前运行,所以它快——能提前减少参与分组的数据量,尤其对大表很关键。
  • HAVING 在分组后运行,是对已经算好的组进行筛选,无法跳过聚合计算。比如 HAVING COUNT(*) > 100,数据库必须先把所有组的计数全算出来,再一个个比。
  • ? 场景对比:查“订单总额超 5000 且下单次数 ≥ 3 的客户”。
    → 先 WHERE order_date >= '2025-01-01' 缩小范围;
    → 再 GROUP BY customer_id
    → 最后 HAVING SUM(amount) > 5000 AND COUNT(*) >= 3

最容易被忽略的是:HAVING 条件里写的别名(比如 AS total),在某些数据库(如 PostgreSQL)里可以直接用,但在 MySQL 8.0 之前不支持——得重复写 SUM(amount) > 5000,不能写 total > 5000。别名可用性取决于具体版本和 SQL 模式,别默认它一定行。

热门栏目