不使用 GROUP BY 的汇总
了解单独使用汇总函数如何将整张表压缩为一行
不使用 GROUP BY 的汇总 是 CoddyKit 上的免费 SQL Interview Prep 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Interview Prep 课程共包含 4 节课。
一个聚合函数,一行
面试官会用这个问题考查一个基础概念:“不使用 GROUP BY 时使用聚合函数会发生什么?”
答案是:整个表会收缩为一行。聚合函数会把所有符合条件的行视为一个大的隐式组。理解这个“隐式组”模型,可以解释许多后续规则,因此让我们仔细建立这个模型。
隐式单组
当您在没有 GROUP BY 的情况下单独使用聚合函数时,SQL 的行为就好像存在一个包含所有行的组。无论表中有多少行,结果始终恰好是一行——即使表为空也是如此。
因此,SELECT COUNT(*) FROM employees 会返回一行,其中包含一个数字,用于概括整个表。
SELECT COUNT(*) AS total_employees
FROM employees;
-- always returns exactly one row同时使用多个聚合函数
您可以在一个 SELECT 中列出多个聚合函数。它们都会概括同一个隐式组,因此结果仍然恰好是一行,只是包含多个列。
这是标准的“给我汇总统计信息”查询。四个数字描述的是同一组完整的行。
SELECT
COUNT(*) AS num_rows,
SUM(salary) AS total_pay,
AVG(salary) AS avg_pay,
MAX(salary) AS top_pay
FROM employees;混用错误
这是最常被考查的规则。没有 GROUP BY 时,您不能在同一个 SELECT 中把单独的聚合函数与未聚合列混用。
为什么?聚合函数会生成一行,但普通列有许多值——它应该显示哪一个?这存在歧义,因此标准 SQL 会引发错误。
-- ERROR: name is not aggregated and there is no GROUP BY
SELECT name, MAX(salary)
FROM employees;为什么会产生歧义
结合我们的表来思考。MAX(salary) 会把所有行收缩为一个值,但 name 在每一行中都有不同的值。单个汇总行无法在一个单元格中容纳五个姓名。
数据库拒绝猜测。这正是 GROUP BY 规则背后的相同原则:每个被选中的列都必须经过聚合,或者属于分组。没有 GROUP BY 时,只允许使用聚合列。
MySQL 的宽松例外
有一个值得特别指出的方言细节:较旧或非严格模式下的 MySQL 会允许这种混用查询,并返回一个任意的姓名——不一定是最高收入者的姓名。
启用 ONLY_FULL_GROUP_BY 的现代 MySQL(现在默认启用)会像其他数据库一样拒绝该查询。提到这一点可以体现您对不同 SQL 方言的了解,但请始终把混用查询视为错误。
获取 MAX 背后的行
那么,如何获取收入最高员工的姓名?不能靠混用。请使用 ORDER BY + LIMIT,或者使用与聚合结果进行比较的子查询。
ORDER BY/LIMIT 版本最简单。子查询版本更容易推广,并且会返回所有并列最高收入的员工。
-- Subquery: returns everyone earning the max
SELECT name, salary
FROM employees
WHERE salary = (SELECT MAX(salary) FROM employees);空表上的聚合函数
面试官可能会埋下这样的边界情况:“单独使用聚合函数时,空表会返回什么?”
COUNT(*)返回 0(一行,值为 0)。SUM、AVG、MIN、MAX返回 NULL(一行,值为 NULL)。
关键在于,您仍然会得到一行结果,绝不会得到零行。这种单行保证正是无 GROUP BY 聚合函数的核心特性。
SELECT COUNT(*) AS c, SUM(salary) AS s, MAX(salary) AS m
FROM employees
WHERE 1 = 0;
-- one row: c=0, s=NULL, m=NULL不能在 WHERE 中使用聚合函数
根据这一模型还可以得出另一条规则:不能把聚合函数放在 WHERE 子句中,因为 WHERE 会在聚合发生之前筛选单独的行。
如果要根据聚合结果进行筛选,应使用 HAVING(配合分组),或者将聚合函数包装在子查询中。按照执行顺序,WHERE 执行得太早,无法看到聚合结果。
-- ERROR: aggregate not allowed in WHERE
-- SELECT * FROM employees WHERE salary > AVG(salary);
-- Correct: compare to the aggregate via subquery
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);单独聚合函数与 GROUP BY 的对比
请这样理解两者的区别:
- 没有 GROUP BY:一个隐式组 = 整个表 = 恰好一行结果。
- 使用 GROUP BY 列:列的每个不同值对应一个组 = 每组一行。
单独使用聚合函数,其实就是分组列数为零的 GROUP BY。同一套机制,只是所有行都放进了一个大桶。
-- Whole table: one row
SELECT AVG(salary) FROM employees;
-- Per department: one row each
SELECT department, AVG(salary)
FROM employees
GROUP BY department;如何解释
一个简洁的回答是:“不使用 GROUP BY 的聚合函数会把整个结果集视为一个隐式组,并且恰好返回一行汇总结果,即使表为空也是如此。您不能同时选择未聚合列,因为该列的值会产生歧义。如果要获取 MAX 或 MIN 背后的行,我会使用带 LIMIT 的 ORDER BY,或者使用与聚合结果进行比较的子查询。”
快速检查
预测输出结构。
回顾
不使用 GROUP BY 时的聚合函数总结:
- 整个表会变成一个隐式组,因此恰好得到一行结果。
- 不能把单独的聚合函数与未聚合列混用。
- 空表:
COUNT(*)= 0,其他函数返回 NULL,但仍然返回一行。 - 聚合函数不能出现在
WHERE中;请使用子查询或HAVING。 - 要获取 MIN/MAX 背后的行,请使用 ORDER BY + LIMIT 或子查询。
聚合函数相关的面试练习到此完成。
用 AI 导师学习 SQL — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 30
- 课程
- 120
常见问题解答
「不使用 GROUP BY 的汇总」课时是免费的吗?
是的 — 「不使用 GROUP BY 的汇总」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 SQL Interview Prep 课程共包含 4 节课。
「不使用 GROUP BY 的汇总」这节课中我会学到什么?
了解单独使用汇总函数如何将整张表压缩为一行 你通过在浏览器中直接运行的动手代码来练习 SQL Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 SQL Interview Prep 需要有经验吗?
无需任何先前经验。CoddyKit 上的 SQL Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「不使用 GROUP BY 的汇总」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 SQL Interview Prep 课中编写并运行代码吗?
能。每节 SQL Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。