多级聚合

过一段时间后,经常更新的表可能会包含大量数据。以之前所示的简单表为例,假设您想要执行多级别查询,例如查询每年在每个类别上的开支金额。

以下查询使用了具有 SUM 函数的 ROLLUP 聚合,可计算各个类别的总开支和所有总开支。NULL 字段表示聚合中的小计值。

  • 只有当 Year 列为 NULL 时,小计才是针对所有 Category 值。

  • YearCategory 列为 NULL 时,小计针对两个列的所有 Amount 值。

使用 ORDER BY 子句,按开支类别、发生开支的年份以及 GROUPING_ID 函数创建的 GROUP BY 级别对结果进行排序:

=> SELECT Category, Year, SUM(Amount) FROM expenses
   GROUP BY ROLLUP(Category, Year) ORDER BY Category, Year, GROUPING_ID();
 Category   | Year |  SUM
------------+------+--------
 Books      | 2005 |  39.98
 Books      | 2007 |  29.99
 Books      | 2008 |  29.99
 Books      |      |  99.96
 Electrical | 2005 | 109.99
 Electrical | 2006 | 109.99
 Electrical | 2007 | 229.98
 Electrical |      | 449.96
            |      | 549.92

同样地,以下查询计算了各年份的总销售以及所有销售总额,然后使用 ORDER BY 子句来对结果进行排序:

=> SELECT Category, Year, SUM(Amount) FROM expenses
   GROUP BY ROLLUP(Year, Category) ORDER BY 2, 1, GROUPING_ID();
  Category  | Year |  SUM
------------+------+--------
 Books      | 2005 |  39.98
 Electrical | 2005 | 109.99
            | 2005 | 149.97
 Electrical | 2006 | 109.99
            | 2006 | 109.99
 Books      | 2007 |  29.99
 Electrical | 2007 | 229.98
            | 2007 | 259.97
 Books      | 2008 |  29.99
            | 2008 |  29.99
            |      | 549.92
(11 rows)

您可以使用 CUBE 聚合来执行所有可能的类别和年份开支分组。以下查询按分组进行了排序,并返回了所有可能的分组:

=> SELECT Category, Year, SUM(Amount) FROM expenses
   GROUP BY CUBE(Category, Year) ORDER BY 1, 2, GROUPING_ID();
 Category   | Year |  SUM
------------+------+--------
 Books      | 2005 |  39.98
 Books      | 2007 |  29.99
 Books      | 2008 |  29.99
 Books      |      |  99.96
 Electrical | 2005 | 109.99
 Electrical | 2006 | 109.99
 Electrical | 2007 | 229.98
 Electrical |      | 449.96
            | 2005 | 149.97
            | 2006 | 109.99
            | 2007 | 259.97
            | 2008 |  29.99
            |      | 549.92

结果包括每个类别每年的小计以及不分年份或类别的所有交易的总计 ($549.92)。

ROLLUPCUBEGROUPING SETS 在分组列生成了 NULL 值以确定小计。如果表数据包括 NULL 值,将这些值与小计中的 NULL 值区分有时非常具有挑战性。

在之前的输出中,Year 列中的 NULL 值表示行在 Category 列(而不是在两个列)进行了分组。在这种情况下,ROLLUP 添加了 NULL 值,以表示小计行。