PostgreSQL GROUPING SETS 用法与实例

本文介绍了如何在 PostgreSQL 中的 GROUP BY 子句中使用 GROUPING SETS 以在一次查询中生成多个维度的报表。

在 PostgreSQL 中,GROUPING SETSGROUP BY 子句的参数,允许您在一次查询中生成多个维度的报表。

比如,要想在一个销售报表中即有每个年份销售额的行,又有每个部门销售额的行,您可以在 GROUP BY 子句中使用 GROUPING SETS 实现它。

PostgreSQL GROUPING SETS 语法

下面的语法说明了如何在 GROUP BY 子句中使用 GROUPING SETS

SELECT ...
FROM table_name
[WHERE ...]
GROUP BY
  GROUPING SETS (
    (group_expr_list_1)
    [, (group_expr_list_2), ...]
  )
;

这里,

  • GROUPING SETSGROUP BY 子句的参数,它必须在 GROUP BY 关键字的后面。
  • (group_expr_list_N) 是一个用于分组的表达式列表,其中可以包含零个或者多个列或表达式,就像在 GROUP BY 子句中直接使用的那些列一样。
  • 您可以为 GROUPING SETS 指定一个或者多个分组表达式,每个分组表达式产生的结果集都将合并到最终的结果集中。
  • (group_expr_list_N) 中没有任何列或者表达式时,即 (),所有符合条件的行都被聚合到一个分组中。

PostgreSQL GROUP BY 实例

我们将使用 Sakila 示例数据库 中的表进行演示,请您先在 PostgreSQL 中安装 Sakila 示例数据库

在 Sakila 示例数据库中, film 表存储了 DVD 商店中的所有影片。

要从 film 表中查找每个影片评级的影片数量,请使用如下语句:

SELECT rating, count(*)
FROM film
GROUP BY rating
ORDER BY rating;
 rating | count
--------+-------
 G      |   178
 PG     |   194
 PG-13  |   223
 R      |   195
 NC-17  |   210
(5 rows)

要从 film 表中查找每个租金的影片数量,请使用如下语句:

SELECT rental_rate, count(*)
FROM film
GROUP BY rental_rate
ORDER BY rental_rate;
 rental_rate | count
-------------+-------
        0.99 |   341
        2.99 |   323
        4.99 |   336
(3 rows)

要想在一个报表中包含上面的两个报表,您可以使用 UNION ALL 将上面的两个结果集合并起来,如下:

SELECT rating, NULL rental_rate, count(*)
FROM film
GROUP BY rating

UNION ALL

SELECT NULL rating, rental_rate, count(*)
FROM film
GROUP BY rental_rate

ORDER BY rating, rental_rate;
 rating | rental_rate | count
--------+-------------+-------
 G      |             |   178  ┐
 PG     |             |   194  │
 PG-13  |             |   223  │ > ranting
 R      |             |   195  │
 NC-17  |             |   210  ┘
        |        0.99 |   341  ┐
        |        2.99 |   323  │ > rental_rate
        |        4.99 |   336  ┘
(8 rows)

但是,上面使用 UNION ALL 的语句看起来很复杂。如果能用一个简单的语句做到这一切,就太棒了。 PostgreSQL GROUPING SETS 可能帮我们做到这一切:

SELECT rating, rental_rate, count(*)
FROM film
GROUP BY GROUPING SETS ((rating), (rental_rate))
ORDER BY rating, rental_rate;
 rating | rental_rate | count
--------+-------------+-------
 G      |             |   178  ┐
 PG     |             |   194  │
 PG-13  |             |   223  │ > ranting
 R      |             |   195  │
 NC-17  |             |   210  ┘
        |        0.99 |   341  ┐
        |        2.99 |   323  │ > rental_rate
        |        4.99 |   336  ┘
(8 rows)

所以,您可以将 GROUPING SETS 简单的理解为对多个分组结果集执行了 UNION ALL 操作。

如果您想在上面的报表中添加一行以显示总影片数量,您可以在 GROUPING SETS 中是一个空的分组表达式 (),如下:

SELECT rating, rental_rate, count(*)
FROM film
GROUP BY GROUPING SETS ((rating), (rental_rate), ())
ORDER BY rating, rental_rate;
 rating | rental_rate | count
--------+-------------+-------
 G      |             |   178
 PG     |             |   194
 PG-13  |             |   223
 R      |             |   195
 NC-17  |             |   210
        |        0.99 |   341
        |        2.99 |   323
        |        4.99 |   336
        |             |  1000

结论

在 PostgreSQL 中的 GROUP BY 子句中,您可以使用 GROUPING SETS 以在一次查询中生成多个分组查询的结果集的集合。

为了应对更加复杂的需求, PostgreSQL 还提供了 ROLLUPCUBE 以简化 GROUPING SETS