SELECT 列的 GROUP BY 规则
了解每个非汇总列为何必须出现在 GROUP BY 中,以及 only-full-group-by 模式
SELECT 列的 GROUP BY 规则 是 CoddyKit 上的免费 Coding Interview Prep 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Coding Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Coding Interview Prep 课程共包含 4 节课。
面试官为什么从 GROUP BY 开始
GROUP BY 是面试中区分初级和中级开发人员的地方。他们测试得最多的一条规则是:SELECT 列表中的每一列都必须包含在聚合函数中,或者列在 GROUP BY 中。
如果违反这条规则,引擎就无法决定对于包含多行的分组应显示哪个值。面试官故意设置这个错误,以确认您理解分组究竟是什么。
分组究竟是什么
GROUP BY 会将多行压缩为每个不同键对应一行。分组后,引擎不再拥有单独的行,只剩下每个分组一行的汇总结果。
- 用于分组的列在每个分组中都有一个明确的值。
- 像
COUNT、SUM、AVG这样的聚合函数,会将多个值归并为一个。 - 任何其他原始列都存在歧义:应该显示多个值中的哪一个?
SELECT department, COUNT(*) AS headcount
FROM employees
GROUP BY department;经典错误
这是面试官最喜欢考的错误:您按 department 分组,却同时选择了 name,而它是一个未聚合且未列在 GROUP BY 中的列。
每个部门有很多员工,因此每个分组中有许多姓名。引擎无法任选一个,因此标准 SQL 会拒绝该查询。
-- ERROR: name is not in GROUP BY and not aggregated
SELECT department, name, COUNT(*)
FROM employees
GROUP BY department;两种修复方式
您有两种合理的修复方式,面试官希望听到您知道两者会产生不同的答案:
- 将该列加入 GROUP BY,如果您确实想要更细的分组(每个部门和姓名一行)。
- 如果希望每个现有分组只得到一个值,请使用
MAX(name)或COUNT(name)这样的聚合函数包裹它。
-- Finer grouping
SELECT department, name, COUNT(*) AS rows_for_person
FROM employees
GROUP BY department, name;MySQL 中的完整分组模式
一个常见陷阱是:较旧版本的 MySQL 允许选择未分组的列,并从分组中悄悄返回任意值。这会产生看似正常的错误报告。
现代 MySQL 默认启用 ONLY_FULL_GROUP_BY,从而强制执行标准规则。Postgres、SQL Server 和 Oracle 一直都执行该规则。如果有人问为什么某个查询“在旧服务器上能运行,现在却出错”,答案就是这个。
-- Legal under ONLY_FULL_GROUP_BY because every
-- selected column is grouped or aggregated
SELECT department, MAX(hire_date) AS latest_hire
FROM employees
GROUP BY department;函数依赖例外
面试官会利用一个细节来测试您的理解深度。如果按某张表的主键分组,那么该表的每个其他列都对这个键存在函数依赖,因此在每个分组中都恰好只有一个值。
Postgres 和现代 MySQL 允许选择这些依赖列,而不必将它们列出。分组键能够唯一确定这些列,因此不存在歧义。
-- Legal: id is the PK, so name is determined by it
SELECT e.id, e.name, COUNT(o.id) AS orders
FROM employees e
LEFT JOIN orders o ON o.employee_id = e.id
GROUP BY e.id;示例解析:按地区统计销售额
假设您必须报告每个地区的销售总额。分组键是 region;度量值是 SUM(amount)。其他所有内容都必须进行聚合或舍弃。
请注意这种结构多么清晰:每个地区一行,每行都带有一个汇总后的值。这就是所有聚合报告采用的结构。
SELECT region,
SUM(amount) AS total_sales,
COUNT(*) AS num_orders,
AVG(amount) AS avg_order
FROM sales
GROUP BY region;混合明细与汇总
一道容易误导的题目是:“显示每个订单的金额及其所在地区的总额。”使用普通 GROUP BY 无法做到这一点,因为分组会破坏单独的行。
正确答案是使用窗口函数(SUM(amount) OVER (PARTITION BY region)),或者将分组子查询连接回来。认识到 GROUP BY 在这里不是正确工具,正是这道题要考察的重点。
-- Detail rows kept, region total added per row
SELECT order_id, region, amount,
SUM(amount) OVER (PARTITION BY region) AS region_total
FROM sales;GROUP BY 与 SELECT 别名
可以按 SELECT 中定义的别名进行 GROUP BY 吗?这取决于具体方言,而这种不一致正是面试官要考察的地方。
- MySQL 和 Postgres:允许按 SELECT 别名分组。
- SQL Server 和 Oracle:不允许;必须重复完整表达式。
可移植的写法是在 GROUP BY 中重复该表达式,这样在哪种数据库中都能工作。
-- Portable: repeat the expression rather than the alias
SELECT EXTRACT(YEAR FROM order_date) AS yr, COUNT(*)
FROM sales
GROUP BY EXTRACT(YEAR FROM order_date);DISTINCT 与 GROUP BY 的唯一性比较
如果只想要不重复的组合且不进行聚合,不带聚合的 GROUP BY 的行为类似于 DISTINCT。面试官可能会问哪种写法更清晰。
使用 DISTINCT 表达意图(“我想要唯一行”)。只有在还要计算聚合值时才使用 GROUP BY。结果相同,但可读性传达的意图不同。
-- These return the same rows
SELECT DISTINCT department, role FROM employees;
SELECT department, role FROM employees GROUP BY department, role;面试中如何表述
遇到 GROUP BY 题目时,请大声说出这条规则:“SELECT 中选出的每一列,要么是分组键,要么被聚合函数包裹,因为分组会为每个键保留一行。”
然后说明您的分组键和度量值,并确认没有列未经分组就混入结果。这种结构化的回答体现了中级水平的能力,即使您还没有写出查询也是如此。
快速检查
请检验您对核心 GROUP BY 规则的掌握程度。
回顾
规则:SELECT 中的每一列都必须是分组键或聚合值。原因:GROUP BY 会为每个键保留一行,因此未分组的原始列会产生歧义。
- 如果违反规则,请将该列加入分组,或对其进行聚合。
- MySQL 的旧行为会返回任意值;
ONLY_FULL_GROUP_BY会强制执行标准。 - 基于主键的函数依赖是唯一的合法例外。
- 如果要让明细行与分组总计并列,请使用窗口函数,而不是 GROUP BY。
常见问题解答
「SELECT 列的 GROUP BY 规则」课时是免费的吗?
是的 — 「SELECT 列的 GROUP BY 规则」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。
「SELECT 列的 GROUP BY 规则」这节课中我会学到什么?
了解每个非汇总列为何必须出现在 GROUP BY 中,以及 only-full-group-by 模式 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Coding Interview Prep 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Coding Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「SELECT 列的 GROUP BY 规则」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Coding Interview Prep 课中编写并运行代码吗?
能。每节 Coding Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- SELECT 列的 GROUP BY 规则
- HAVING 与 WHERE
- 按多列和表达式分组
- 统计并筛选分组