MySQL ROLLUP

17 Mar 2025 | 6 分钟阅读

MySQL 中的 ROLLUP 是一个修饰符,用于生成摘要输出,包括表示超聚合(更高层次)摘要操作的额外行。它使我们能够使用单个查询在多个分析级别汇总输出。它主要用于支持 OLAP(在线分析处理)操作。

ROLLUP 修饰符只能与 MySQL 中的 GROUP BY 查询一起使用。

语法

以下是使用 ROLLUP 修饰符的语法:

在此语法中,我们需要在 SELECT 子句中指定查询结果中显示的列名。接下来,我们将提及表名。之后,我们指定了 GROUP BY 子句,包括我们希望基于其聚合数据的列名。最后,我们指定 WITH ROLLUP 修饰符以在附加行中获取超聚合输出。

我们已经了解到 GROUP BY 查询与聚合函数(如 MAXMINSUMCOUNTAVG 等)一起使用,这些函数按单列或多列对输出行进行分组。ROLLUP 修饰符是 GROUP BY 查询的一个选项,它包含用于表示小计的额外字段。这些附加行称为超聚合行,它是总计行的组合。因此,ROLLUP 修饰符允许我们根据 MySQL 中的 GROUP BY 子句中指定的列,在单个查询中创建多组行。

MySQL ROLLUP 解释

如果我们想理解 ROLLUP 修饰符,我们必须知道什么是分组集。分组集是我们想要分组以获取结果输出的列集。例如,假设我们有一个表 "sales",其中包含以下数据:

MySQL ROLLUP

如果我们要按年汇总结果,我们将使用简单的 GROUP BY 子句,如下所示:

它将给出以下输出,显示每年的总(聚合)销售额:

MySQL ROLLUP

在上述查询中,分组集由列名 Year 表示。如果我们需要在单个查询中同时生成多个分组集,我们可以使用 UNION ALL 运算符,如下所示:

在此查询中,我们可以看到 NULL 列。这是因为 UNION ALL 子句要求所有查询具有相同数量的列。因此,为了满足此要求,我们在第二个查询的 select 列表中添加了 NULL。

执行查询后,我们得到以下输出:

MySQL ROLLUP

Year 列输出中的 NULL 表示总计超聚合值。虽然此查询能够生成每年的总销售额以及总计聚合销售额,但它存在两个问题:

  1. 它使查询相当冗长。
  2. 它降低了查询性能,因为数据库引擎在内部执行两个单独的查询并将结果集组合成一个输出。

为了解决这些问题,MySQL 允许我们使用 ROLLUP 子句,它在一个查询中提供两个分析级别。ROLLUP 子句是 GROUP BY 子句的扩展,它生成另一行并显示总计(超聚合)值。

让我们看看在 GROUP BY 子句中添加 WITH ROLLUP 修饰符后的结果,它显示了所有年份值的总计:

执行此命令后,我们将得到以下输出:

MySQL ROLLUP

在此输出中,我们可以在Year 列中看到 NULL 值,它标识了超聚合行。它清楚地表明 ROLLUP 子句不仅生成小计,而且还给出所有年份总销售额的总计。

如果 GROUP BY 子句包含多列,则 ROLLUP 修饰符会产生更复杂的效果。在这种情况下,ROLLUP 修饰符假定 GROUP BY 子句中指定的列之间存在层次结构。每当列值发生变化时,查询都会在结果末尾生成一个额外的超聚合摘要行。

例如,假设我们在 GROUP BY 子句中指定了三列,如下所示:

ROLLUP 修饰符假定层次结构如下:

并生成以下分组集:

请参阅以下查询以更清楚地解释它:

如果没有 ROLLUP,基于 GROUP BY 子句中指定的多列的 sales 表摘要如下所示。在这里,我们将仅在 Year/Country/Product 分析级别获得摘要值。

MySQL ROLLUP

添加 ROLLUP 后,查询会生成几个额外的行:

请参见下面的输出

MySQL ROLLUP

上述输出生成了四个分析级别的信息,解释如下:

  • 首先,给定年份和国家/地区的产品行的每个集合都会生成一个额外的超聚合摘要行,显示所有产品的总计。它将产品列设置为 NULL。
  • 接下来,给定年份的每个行集合都会生成一个额外的超聚合摘要行,显示所有国家/地区和产品的总计。它将国家/地区和产品列设置为 NULL。
  • 最后,对于所有其他行,它会生成一个额外的超聚合摘要行,显示所有列的总计。它将年份、国家/地区和产品列设置为 NULL。

如果我们更改 GROUP BY 列中指定的列的顺序,我们将得到不同的结果:

请参阅以下输出:

MySQL ROLLUP

GROUPING() 函数

GROUPING() 函数用于检查结果集中的 NULL 是表示常规分组值、超聚合值还是总计。当 NULL 出现在超聚合行中时,它返回 1。否则,它返回 0。

我们可以在 select 列表、HAVING 子句和 ORDER BY 子句中使用 GROUPING() 函数。

请参阅以下查询:

我们将得到以下输出,其中当 Year 列中的 NULL 出现在超聚合行中时,GROUPING(Year) 返回 1。否则,它将返回 0。

同样,当 Country 列中的 NULL 出现在超聚合行中时,GROUPING(Country) 返回 1。否则,它将返回 0。

此外,当 Product 列中的 NULL 出现在超聚合行中时,GROUPING(Product) 返回 1。否则,它将返回 0。

MySQL ROLLUP

我们还可以使用 GROUPING() 函数为超聚合 NULL 值替换有意义的标签,而不是直接显示它们。

以下查询解释了如何将 IF() 函数与 GROUPING() 函数结合使用,以替换 Year、Country 和 Product 列中超聚合 NULL 值的标签:

我们将得到以下输出:

MySQL ROLLUP

如果 GROUPING() 函数中有多个参数,它将返回一个表示位掩码的输出,该位掩码结合了每个表达式的结果。在这里,最低位生成最右边参数的结果。以下示例将这样评估:

示例: GROUPING (Year, Country, Product)

如果任何参数具有超聚合 NULL 值,则此类 GROUPING() 的结果为非零。在这种情况下,它将只返回超聚合行并使用以下查询过滤常规分组行:

它将显示以下输出

MySQL ROLLUP
下一主题MySQL INT