0Pricing
SQL Academy · 课时

超越单个 GROUP BY

在多个层级进行聚合

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

单个 GROUP BY 的局限性

标准的 GROUP BY 子句可以让您在一个特定层级上聚合行,例如统计每个地区的销售总额。但如果您还想在同一个查询中获得每个产品类别的总额以及总计,该怎么办?

将查询重复三次并使用 UNION ALL 虽然可行,但既冗长又缓慢。SQL 提供了三个强大的扩展——GROUPING SETS、ROLLUP 和 CUBE——可以在一次扫描中优雅地解决这个问题。

SELECT region, SUM(amount) AS total_sales
FROM sales
GROUP BY region;

设置示例表

在本课中,我们将使用一个简单的 sales 表,该表记录每笔销售的 区域、类别 和 金额。让我们创建并填充该表,这样接下来的每个查询都能结合上下文理解。

CREATE TABLE sales (
  id       SERIAL PRIMARY KEY,
  region   TEXT,
  category TEXT,
  amount   NUMERIC
);

INSERT INTO sales (region, category, amount) VALUES
  ('North', 'Electronics', 1200),
  ('North', 'Clothing',     800),
  ('South', 'Electronics',  950),
  ('South', 'Clothing',     600),
  ('East',  'Electronics', 1100),
  ('East',  'Clothing',     750);

什么是 GROUPING SETS?

GROUPING SETS 允许您在一个 GROUP BY 子句中定义多个相互独立的分组层级。列表中的每个集合都会生成自己的一组行,就像分别编写查询,再使用 UNION ALL 将它们合并一样。

语法如下:GROUP BY GROUPING SETS ( (col1, col2), (col1), () )。空集合 () 表示所有行的总计。

SELECT region, category, SUM(amount) AS total
FROM sales
GROUP BY GROUPING SETS (
  (region, category),
  (region),
  ()
);

读取 GROUPING SETS 输出

运行 GROUPING SETS 查询时,不同分组层级的行会堆叠在一起。对于特定集合不包含的列,该行中会显示为 NULL。

例如,属于 (region) 集合的行会在 category 列中显示 NULL,这表示该总计涵盖该区域的所有类别。总计行(空集合)会在 region 和 category 两列中都显示 NULL。

SELECT
  COALESCE(region,   'ALL REGIONS')   AS region,
  COALESCE(category, 'ALL CATEGORIES') AS category,
  SUM(amount) AS total
FROM sales
GROUP BY GROUPING SETS (
  (region, category),
  (region),
  ()
)
ORDER BY region NULLS LAST, category NULLS LAST;

介绍 ROLLUP

ROLLUP 是常见分组集合层级的简写。给定列 (A, B) 后,ROLLUP(A, B) 会自动生成以下集合:(A, B)、(A) 和 ()。

这非常适合处理层级数据,例如从年到月再到日,或从区域到类别。生成的集合数量始终为 n + 1,其中 n 是列的数量。

-- ROLLUP(region, category) is equivalent to:
-- GROUPING SETS ( (region, category), (region), () )

SELECT region, category, SUM(amount) AS total
FROM sales
GROUP BY ROLLUP(region, category)
ORDER BY region NULLS LAST, category NULLS LAST;

三个层级的 ROLLUP

向 ROLLUP 添加第三列后,层级会再扩展一级。ROLLUP(A, B, C) 会生成四个集合:(A, B, C)、(A, B)、(A) 和 ()。

在下面的示例中,year 是最外层级,category 是粒度最细的层级。该查询会在层级的每一步生成小计,此外还会生成一行总计。

SELECT
  year,
  region,
  category,
  SUM(amount) AS total
FROM (
  VALUES
    (2024, 'North', 'Electronics', 1200),
    (2024, 'North', 'Clothing',     800),
    (2024, 'South', 'Electronics',  950),
    (2025, 'North', 'Electronics', 1400),
    (2025, 'South', 'Clothing',     700)
) AS t(year, region, category, amount)
GROUP BY ROLLUP(year, region, category)
ORDER BY year NULLS LAST, region NULLS LAST, category NULLS LAST;

介绍 CUBE

CUBE 比 ROLLUP 更为全面。给定 n 列后,它会生成分组集合的 所有 2^n 种可能组合,其中包括总计。

对于 CUBE(region, category),生成的集合为:(region, category)、(region)、(category) 和 (),总共四个集合。当您希望查看各个方向上的横向总计,而不只是单一层级时,这会非常有用。

-- CUBE(region, category) produces:
-- GROUPING SETS ( (region,category), (region), (category), () )

SELECT region, category, SUM(amount) AS total
FROM sales
GROUP BY CUBE(region, category)
ORDER BY region NULLS LAST, category NULLS LAST;

CUBE 与 ROLLUP——何时使用哪一个

请选择适合您数据维度自然层级的方式:

  • 当列具有层级关系(例如从国家到城市再到门店)时使用 ROLLUP。小计只会沿一条路径逐级汇总。
  • 当列是相互独立的维度(例如区域和类别),并且您希望查看所有可能的横向组合时,使用 CUBE。
  • 当您需要完全控制分组方式,而 ROLLUP 和 CUBE 都无法满足确切要求时,使用 GROUPING SETS。

GROUPING() 函数

由于 NULL 既可能表示实际缺失值,也可能表示分组占位符,SQL 提供了 GROUPING() 函数。当某列属于超聚合(占位符)行时,它返回 1;当该列确实参与分组时,返回 0。

这样,您就可以区分真正的 NULL 区域值和涵盖所有区域的小计行。

SELECT
  region,
  category,
  SUM(amount)        AS total,
  GROUPING(region)   AS is_region_subtotal,
  GROUPING(category) AS is_category_subtotal
FROM sales
GROUP BY CUBE(region, category)
ORDER BY region NULLS LAST, category NULLS LAST;

使用 GROUPING() 标记行

一种常见做法是将 GROUPING() 与 CASE 表达式结合起来,用易于理解的标签替代原始的 NULL 值。这样,报表中的 ROLLUP 或 CUBE 查询输出会更易于阅读。

SELECT
  CASE GROUPING(region)
    WHEN 1 THEN 'Grand Total'
    ELSE region
  END AS region_label,
  CASE GROUPING(category)
    WHEN 1 THEN 'All Categories'
    ELSE category
  END AS category_label,
  SUM(amount) AS total
FROM sales
GROUP BY ROLLUP(region, category)
ORDER BY GROUPING(region), region, GROUPING(category), category;

将固定列与 ROLLUP 混用

您可以在同一个子句中将常规 GROUP BY 列与 ROLLUP 或 CUBE 混用。列在 ROLLUP(...) 外部列出时,会始终包含在每个分组集合中,永远不会被逐级汇总。

在下面的查询中,year 是固定的分组列,而 region 和 category 参与逐级汇总。因此,您会得到按年份划分的小计,而不是跨所有年份的总计。

SELECT
  2024           AS year,
  region,
  category,
  SUM(amount)    AS total
FROM sales
GROUP BY 2024, ROLLUP(region, category)
ORDER BY region NULLS LAST, category NULLS LAST;

快速检查

测试您对 GROUPING SETS、ROLLUP 和 CUBE 的理解。

回顾——超越单个 GROUP BY

在本课中,您学习了三个强大的 SQL 扩展,它们可以让您在单个查询中生成多个汇总层级:

  • GROUPING SETS——完全手动控制;列出您确切需要的组合。
  • ROLLUP——非常适合层级数据;从最详细的层级逐级汇总到总计。
  • CUBE——生成所列维度的所有可能横向组合。

您还学会了使用 GROUPING() 区分真正的 NULL 值和超聚合占位行,以及使用 CASE GROUPING(...) 模式生成整洁、易读的报表输出。

每当您需要多维汇总时,这些工具都不可或缺——透视式报表、仪表板和数据仓库查询都高度依赖它们。

常见问题解答

「超越单个 GROUP BY」课时是免费的吗?

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

「超越单个 GROUP BY」这节课中我会学到什么?

在多个层级进行聚合 你通过在浏览器中直接运行的动手代码来练习 SQL Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 SQL Academy 需要有经验吗?

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

「超越单个 GROUP BY」课时需要多长时间?

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

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

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

此课程中的所有课时

  1. 超越单个 GROUP BY
  2. 使用 ROLLUP 计算小计
  3. 使用 CUBE 处理所有组合
  4. GROUPING SETS 详解
← 返回 SQL Academy