0Pricing
SQL Academy · 课时

HAVING 与 WHERE

区分 HAVING(过滤分组)和 WHERE(过滤行),并在同一查询中正确使用二者。

HAVING 与 WHERE 是 CoddyKit 上的免费 SQL Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Academy 课程共包含 4 节课。

两个筛选阶段

WHERE 在分组之前筛选单独的行。HAVING 在聚合之后筛选分组。它们看起来相似,但作用于不同阶段。

WHERE 示例

WHERE 筛选原始行。它无法查看聚合结果:

-- Sum totals for rows where status is 'paid':
SELECT user_id, SUM(total) AS revenue
FROM orders
WHERE status = 'paid'
GROUP BY user_id;

HAVING 示例

HAVING 筛选分组。它可以引用聚合结果:

SELECT user_id, COUNT(*) AS order_count
FROM orders
GROUP BY user_id
HAVING COUNT(*) >= 5;     -- only users with ≥ 5 orders

组合使用 WHERE 和 HAVING

同一个查询中可以同时使用两者:

SELECT user_id, SUM(total) AS revenue
FROM orders
WHERE created_at >= NOW() - INTERVAL '90 days'
GROUP BY user_id
HAVING SUM(total) > 1000;

不要在 WHERE 中使用聚合函数

规划器会在分组之前执行 WHERE,此时聚合结果还不可用:

-- WRONG:
SELECT user_id, COUNT(*) FROM orders
WHERE COUNT(*) > 5         -- ERROR
GROUP BY user_id;

-- RIGHT — move to HAVING:
SELECT user_id, COUNT(*) FROM orders
GROUP BY user_id
HAVING COUNT(*) > 5;

尽可能将谓词下推到 WHERE

WHERE 会在分组之前进行筛选,因此进入聚合阶段的行更少。只有无法用 WHERE 表达的条件,才应使用 HAVING。

-- Slightly slower (filters after grouping):
SELECT user_id, COUNT(*) FROM orders
GROUP BY user_id
HAVING user_id IN (1,2,3);

-- Faster (filters before grouping):
SELECT user_id, COUNT(*) FROM orders
WHERE user_id IN (1,2,3)
GROUP BY user_id;

逻辑执行顺序

概念上的执行顺序:

  1. FROM — 选择表并进行连接
  2. WHERE — 筛选行
  3. GROUP BY — 创建分组
  4. HAVING — 筛选分组
  5. SELECT — 投影列
  6. ORDER BY — 排序
  7. LIMIT — 取前 N 条

不使用 GROUP BY 的 HAVING

您可以在没有 GROUP BY 的情况下使用 HAVING——整张表会成为一个分组:

SELECT SUM(total) FROM orders
HAVING SUM(total) > 1000000;       -- prints only if total over 1M

HAVING 中的别名

有些数据库允许 HAVING 引用 SELECT 别名;PostgreSQL 支持,MySQL 也支持,而标准 SQL 不支持。为了获得最佳可移植性,请重复写出聚合表达式:

SELECT user_id, COUNT(*) AS order_count
FROM orders
GROUP BY user_id
HAVING COUNT(*) >= 5;       -- portable
-- HAVING order_count >= 5  -- works in PG / MySQL

HAVING 与多个聚合函数

对于由多个聚合条件组成的条件,请使用 HAVING:

SELECT user_id, COUNT(*) AS orders, SUM(total) AS revenue
FROM orders
GROUP BY user_id
HAVING COUNT(*) >= 5 AND SUM(total) > 1000;

性能提示

HAVING 中的聚合筛选无法像针对列使用 WHERE 那样利用索引。请将能移到 WHERE 的条件移过去。

回顾

WHERE = 筛选行。HAVING = 筛选分组。

  • 聚合条件只能放在 HAVING 中,不能放在 WHERE 中
  • 将谓词下推到 WHERE 以提升速度
  • 根据需要同时使用两者

快速检查

您希望找出下过超过 10 个订单的用户。应该使用哪个子句进行筛选?

常见问题解答

「HAVING 与 WHERE」课时是免费的吗?

是的 — 「HAVING 与 WHERE」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Academy 课程的其余内容,请升级到 CoddyKit PRO。 SQL Academy 课程共包含 4 节课。

「HAVING 与 WHERE」这节课中我会学到什么?

区分 HAVING(过滤分组)和 WHERE(过滤行),并在同一查询中正确使用二者。 你通过在浏览器中直接运行的动手代码来练习 SQL Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 SQL Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 SQL Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「HAVING 与 WHERE」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 SQL Academy 课中编写并运行代码吗?

能。每节 SQL Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. COUNT、SUM、AVG、MIN、MAX
  2. 按单列与多列 GROUP BY
  3. HAVING 与 WHERE
  4. 常见陷阱:聚合中的 NULL
← 返回 SQL Academy