2024 年 9 月 26 日: PostgreSQL 17 发布!
支持的版本: 当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本: devel
不支持的版本: 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 支持聚集函数。聚集函数从多行输入计算单个结果。例如,有聚集函数来计算计数求和平均值最大值最小值

例如,我们可以找到任何地方的最高低温值。

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

如果我们想知道该值出现在哪个城市(或哪些城市),我们可以尝试

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

但是这行不通,因为聚集函数最大值不能用于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 节中进行了说明。

理解聚集函数与WHEREHAVING子句之间的交互非常重要。SQLWHEREHAVING子句之间的根本区别在于: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 的读取值。

提交更正

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