🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 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); _错误_ ``` 不过这个方法不能运转,因为聚集函数`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, max(temp_lo) FROM weather GROUP BY city; ``` ``` city | max ---------------+----- Hayward | 37 San Francisco | 46 (2 rows) ``` 这样每个城市一个输出。每个聚集结果都是在匹配该城市的行上面计算的。 我们可以用`HAVING`过滤这些分组: ``` SELECT city, max(temp_lo) FROM weather GROUP BY city HAVING max(temp_lo) < 40; ``` ``` city | max ---------+----- Hayward | 37 (1 row) ``` 这样就只给出那些`temp_lo`值曾经有低于 40 度的城市。最后, 如果我们只关心那些名字以"`S`"开头的城市,我们可以用: ``` SELECT city, max(temp_lo) FROM weather WHERE city LIKE 'S%'<a name="CO.TUTORIAL-AGG-LIKE">**(1)**</a> GROUP BY city HAVING max(temp_lo) < 40; ``` [**(1)**](#calibre_link-1399) 语句中的`LIKE`执行模式匹配,在[Section 9.7](#calibre_link-1400)里有解释。 理解聚集和SQL的`WHERE`和`HAVING` 子句之间的关系非常重要。`WHERE`和`HAVING`的基本区别如下: `WHERE`在分组和聚集计算之前选取输入行(它控制哪些行进入聚集计算), 而`HAVING`在分组和聚集之后选取输出行。因此,`WHERE` 子句不能包含聚集函数;因为试图用聚集函数判断那些行将要输入给聚集运算是没有意义的。 相反,`HAVING`子句总是包含聚集函数。当然,你可以写不使用聚集的`HAVING` 子句,但这样做没什么好处,因为同样的条件用在`WHERE`阶段会更有效。 在前面的例子里,我们可以在`WHERE`里应用城市名称限制,因为它不需要聚集。 这样比在`HAVING`里增加限制更加高效,因为我们避免了为那些未通过 `WHERE`检查的行进行分组和聚集计算。