支持的版本: 当前 (17) / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2

2.7. 聚合函数 #

和大多数其他关系数据库产品一样,PostgreSQL 支持聚合函数。聚合函数从多个输入行计算单个结果。例如,有一些聚合函数可以计算一组行上的countsumavg(平均值)、max(最大值)和min(最小值)。

例如,我们可以使用以下方式找到任何地方的最低温度读数中的最高值:

SELECT max(temp_lo) FROM weather;
 max
-----
  46
(1 row)

如果我们想知道该读数发生在哪个城市(或哪些城市),我们可以尝试

SELECT city FROM weather WHERE temp_lo = max(temp_lo);     WRONG

但这行不通,因为聚合函数 max 不能在 WHERE 子句中使用。(之所以存在此限制,是因为 WHERE 子句确定哪些行将包含在聚合计算中;因此显然它必须在计算聚合函数之前进行评估。)但是,通常情况下,可以重新陈述查询以实现所需的结果,这里通过使用子查询

SELECT city FROM weather
    WHERE temp_lo = (SELECT max(temp_lo) FROM weather);
     city
---------------
 San Francisco
(1 row)

这是可以的,因为子查询是一个独立的计算,它与外部查询中发生的情况分开计算自己的聚合。

聚合函数与 GROUP BY 子句结合使用也非常有用。例如,我们可以使用以下方式获取每个城市的读数数量和观察到的最大最低温度:

SELECT city, count(*), max(temp_lo)
    FROM weather
    GROUP BY city;
     city      | count | max
---------------+-------+-----
 Hayward       |     1 |  37
 San Francisco |     2 |  46
(2 rows)

这会为我们提供每个城市一行输出。每个聚合结果都是根据与该城市匹配的表行计算的。我们可以使用 HAVING 过滤这些分组的行:

SELECT city, count(*), max(temp_lo)
    FROM weather
    GROUP BY city
    HAVING max(temp_lo) < 40;
  city   | count | max
---------+-------+-----
 Hayward |     1 |  37
(1 row)

这只为我们提供了所有 temp_lo 值都低于 40 的城市的相同结果。最后,如果我们只关心名称以S开头的城市,我们可以这样做:

SELECT city, count(*), max(temp_lo)
    FROM weather
    WHERE city LIKE 'S%'            -- (1)
    GROUP BY city;
     city      | count | max
---------------+-------+-----
 San Francisco |     2 |  46
(1 row)

(1)

LIKE 运算符执行模式匹配,并在 第 9.7 节中进行了解释。

重要的是要理解聚合函数与SQLWHEREHAVING 子句之间的交互。 WHEREHAVING 之间的根本区别在于:WHERE 在计算组和聚合之前选择输入行(因此,它控制哪些行进入聚合计算),而 HAVING 在计算组和聚合之后选择组行。因此,WHERE 子句不得包含聚合函数;尝试使用聚合来确定哪些行将作为聚合的输入毫无意义。另一方面,HAVING 子句始终包含聚合函数。(严格来说,您允许编写不使用聚合的 HAVING 子句,但这很少有用。相同的条件可以在 WHERE 阶段更有效地使用。)

在前面的示例中,我们可以在 WHERE 中应用城市名称限制,因为它不需要聚合。这比将限制添加到 HAVING 更有效,因为我们避免了对所有未通过 WHERE 检查的行执行分组和聚合计算。

选择进入聚合计算的行的另一种方法是使用 FILTER,这是一个按聚合选项进行的:

SELECT city, count(*) FILTER (WHERE temp_lo < 45), max(temp_lo)
    FROM weather
    GROUP BY city;
     city      | count | max
---------------+-------+-----
 Hayward       |     1 |  37
 San Francisco |     1 |  46
(2 rows)

FILTER 很像 WHERE,只是它仅从附加到的特定聚合函数的输入中删除行。在这里,count 聚合仅计算 temp_lo 低于 45 的行;但是 max 聚合仍然应用于所有行,因此它仍然找到 46 的读数。

提交更正

如果您在文档中看到任何不正确的内容、与您使用特定功能的体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。