2025年9月25日: PostgreSQL 18 发布!
支持的版本:当前 (18) / 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支持聚合函数。聚合函数从多个输入行计算单个结果。例如,有一些聚合函数可以计算行集合上的count(计数)、sum(求和)、avg(平均值)、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 meget 像 WHERE,但它只从它所附加的特定聚合函数的输入中删除行。在这里,count聚合函数只计算temp_lo低于45的行;但max聚合函数仍然应用于所有行,因此它仍然找到46的读数。

提交更正

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