按多列和表达式分组
掌握组合分组键,以及如何按计算值分组
按多列和表达式分组 是 CoddyKit 上的免费 Coding Interview Prep 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Coding Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Coding Interview Prep 课程共包含 4 节课。
超越单个分组键
实际报表很少只按一列分组。面试官会将问题从'按地区统计销售额'升级为'按地区、按月份统计销售额',以了解您是否理解复合分组键。
规则可以直接扩展:在 GROUP BY 中列出更多列,就会为这些列的每个不同组合创建一行。
多列意味着什么
当您写出 GROUP BY region, product 时,分组键就是(地区,产品)这一对值。每个不同的组合都会成为一行输出。
- 5 个地区和 4 种产品最多会产生 20 个分组。
- 从未出现过的组合不会生成任何行。
- GROUP BY 中列的顺序不会改变结果集,只是有时会影响执行计划。
SELECT region, product, SUM(amount) AS total
FROM sales
GROUP BY region, product;仍须遵守 SELECT 规则
核心约束并没有放宽。SELECT 中每个非聚合列都必须出现在 GROUP BY 中。对于复合键,只需将这些列全部列出即可。
在多键分组中漏掉一列,是面试压力下最常见的疏漏。请确保 GROUP BY 列表与 SELECT 中的非聚合列完全对应。
-- Both region and product appear in GROUP BY
SELECT region, product,
COUNT(*) AS orders,
AVG(amount) AS avg_amount
FROM sales
GROUP BY region, product;按表达式分组
您可以按计算值分组,而不仅仅是按原始列分组。一个常见要求是按月份统计销售额,这意味着要按截断后的日期或提取出的日期部分分组。
GROUP BY 中的表达式必须与 SELECT 中的表达式一致。数据库引擎会按照计算结果进行分组。
SELECT DATE_TRUNC('month', order_date) AS month,
SUM(amount) AS monthly_total
FROM sales
GROUP BY DATE_TRUNC('month', order_date);使用 CASE 分桶
一种强大的模式是按 CASE 表达式分组,从而创建自定义分桶。这样无需查找表,就能生成'小额 / 中额 / 大额订单'汇总。
面试官喜欢这个问题,因为它会同时测试 CASE 逻辑和按派生值分组的能力。
SELECT CASE
WHEN amount < 50 THEN 'small'
WHEN amount < 200 THEN 'medium'
ELSE 'large'
END AS bucket,
COUNT(*) AS orders
FROM sales
GROUP BY CASE
WHEN amount < 50 THEN 'small'
WHEN amount < 200 THEN 'medium'
ELSE 'large'
END;按列位置分组
许多数据库方言允许按序号位置分组:GROUP BY 1, 2 表示按 SELECT 中的第一列和第二列分组。这种写法简洁,但很脆弱。
面试官可能会接受这种写法,但请注意其中的风险:重新排列 SELECT 列表会悄悄改变分组方式。在生产代码中,请优先使用明确的表达式。
-- 1 = month expression, 2 = region
SELECT DATE_TRUNC('month', order_date) AS month,
region, SUM(amount)
FROM sales
GROUP BY 1, 2;NULL 会形成独立分组
分组中的一个 NULL 处理陷阱是:当分组列包含 NULL 时,所有 NULL 行都会合并为一个分组。
这与相等比较不同,在相等比较中 NULL 永远不等于 NULL。但在分组时,NULL 会被视为'相同',并形成一个分桶。面试官很喜欢这个看似矛盾的现象。
-- Rows with region IS NULL all land in one group
SELECT region, COUNT(*) AS orders
FROM sales
GROUP BY region;使用 GROUPING SETS 生成多个层级
如果要在一个查询中生成多个分组粒度,请使用 GROUPING SETS。它会计算列出的每组键,并将结果合并起来。
这体现了中高级水平:无需编写三个独立查询再使用 UNION,一个语句就能同时返回按地区、按产品的汇总以及总计。
SELECT region, product, SUM(amount) AS total
FROM sales
GROUP BY GROUPING SETS ((region), (product), ());ROLLUP 和 CUBE
ROLLUP 和 CUBE 是常见分组集合的简写。ROLLUP(region, product) 会生成地区加产品的明细、地区小计以及总计,非常适合层级报表。
CUBE 会生成所列各列的所有组合。了解这些功能,可以体现候选人确实编写过实际的报表查询。
SELECT region, product, SUM(amount) AS total
FROM sales
GROUP BY ROLLUP (region, product);示例:按月统计地区报表
综合运用这些概念:统计每个地区每个月的销售总额和平均销售额,只保留已完成的订单,并按便于阅读的方式排序。
WHERE 先缩小行的范围,复合键按地区和月份表达式分组,ORDER BY 则排列输出结果。这是数据分析师面试中典型的完整回答。
SELECT region,
DATE_TRUNC('month', order_date) AS month,
SUM(amount) AS total,
AVG(amount) AS avg_order
FROM sales
WHERE status = 'completed'
GROUP BY region, DATE_TRUNC('month', order_date)
ORDER BY region, month;如何清晰地说出推理过程
遇到任何复合分组问题时,请明确说出分组键:'我按 X 和 Y 的组合进行分组,因此每个不同的(X,Y)组合都会得到一行。'
然后确认每个非聚合的 SELECT 列都包含在该键中,并说明 NULL 会合并为一个分组。这种有条理的讲解方式正是中级面试所看重的。
快速检查
请思考复合分组键的工作方式。
回顾
复合键:列出多列会为每个不同组合生成一行;每个非聚合的 SELECT 列都必须包含在该键中。
- 您可以按表达式、CASE 分桶或序号位置分组(按位置分组很脆弱)。
- 分组列中的 NULL 会合并为一个分组。
GROUPING SETS、ROLLUP和CUBE可以在一个查询中生成多个分组层级。- 请在分组前将行筛选条件放入 WHERE。
常见问题解答
「按多列和表达式分组」课时是免费的吗?
是的 — 「按多列和表达式分组」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。
「按多列和表达式分组」这节课中我会学到什么?
掌握组合分组键,以及如何按计算值分组 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Coding Interview Prep 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Coding Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「按多列和表达式分组」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Coding Interview Prep 课中编写并运行代码吗?
能。每节 Coding Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。