聚集函数
和大多数其它关系数据库产品一样, 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)这样做是 OK 的,因为子查询是一次独立的计算,它独立于外层的查询计算出自己的聚集。
聚集同样也常用于 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%'(1) GROUP BY city HAVING max(temp_lo) < 40; LIKE 做模式匹配,在 Section 里有解释。
理解聚集和sql的 WHERE 以及 HAVING 子句之间的关系对我们非常重要。 WHERE 和 HAVING 的基本区别如下: WHERE 在分组和聚集计算之前选取输入行(因此,它控制哪些行进入聚集计算), 而 HAVING 在分组和聚集之后选取分组的行。 因此,WHERE 子句不能包含聚集函数; 因为试图用聚集函数判断那些行输入给聚集运算是没有意义的。 相反,HAVING 子句总是包含聚集函数。 (严格说来,你可以写不使用聚集的 HAVING 子句, 但这样做只是白费劲。同样的条件可以更有效地用于 WHERE 阶段。)
在前面的例子里,我们可以在 WHERE 里应用城市名称限制,因为它不需要聚集。 这样比在 HAVING 里增加限制更加高效,因为我们避免了为那些未通过 WHERE 检查的行进行分组和聚集计算。
聚集函数对一组值进行操作以返回单个标量值。可以在查询和子查询方法中使用这些函数。
以下示例描述聚集:SELECT SUM (e.salary) FROM EmpBean e WHERE e.dept.deptno =20
此聚集计算第 20 个部门的总计月薪。
聚集函数是 AVG、COUNT、MAX、MIN 和 SUM。以下示例中描述了聚集函数的语法:aggregation-function ( [ ALL | DISTINCT ] expression )或:COUNT( [ ALL | DISTINCT ] identification-variable )或:COUNT( * )
在应用函数之前,DISTINCT 选项消除重复值。ALL 是缺省选项,并且不消除重复。计算聚集函数时,除了 COUNT(*) 和 COUNT(identification-variable)(它们返回此集合中的所有元素的计数值),空值都被忽略。
如果您的数据存储是 Informix,那么当使用 COUNT 函数或 SUM、AVG、MIN 和 MAX 函数的 DISTINCT 格式时,必须将表达式参数限定为单个值的路径表达式。
定义返回类型 对于使用聚集函数的选择方法,您可以将返回类型定义为基本类型或包装器类型。返回类型必须与来自数据存储的返回类型兼容。MAX 和 MIN 函数可以应用于任何数字、字符串或日期时间数据类型并返回相应的数据类型。SUM 和 AVG 函数采用数字类型作为输入,并返回数据存储中使用的同一数字类型。COUNT 函数可以采用任何数据类型,并返回整数。
当应用于空集时,SUM、AVG、MAX 和 MIN 函数可以返回 null 值。当 COUNT 函数应用于空集时,它返回零(0)。如果返回值可能是 NULL,那么使用包装器类型;否则,容器会显示 ObjectNotFound 异常。
使用 GROUP BY 和 HAVING 用于聚集函数的值的集合是由查询的 FROM 和 WHERE 子句产生的集合来确定的。您可以将该集合分成几个组,并将聚集函数应用于每个组。要执行此操作,请在查询中使用 GROUP BY 子句。GROUP BY 子句定义组成路径表达式列表的分组成员。每个路径表达式指定作为基本类型(byte、short、int、long、float、double、boolean、char)或包装器类型(Byte、Short、Integer、Long、Float、Double、BigDecimal、String、Boolean、Character、java.util.Calendar、java.util.Date、 java.sql.Date、java.sql.Time 或 java.sql.Timestamp)的字段。
以下示例描述计算每个部门的平均月薪的查询中 GROUP BY 子句的使用:
SELECT e.dept.deptno,AVG ( e.salary) FROM EmpBean e GROUP BY e.dept.deptno将集合分为几个组时,认为一个 NULL 值等于另一个 NULL 值。
正如 WHERE 子句从 FROM 子句过滤元组(即,返回多值的记录),可以使用测试组属性(涉及聚集函数或分组成员)的 HAVING 子句来过滤组:SELECT e.dept.deptno,AVG ( e.salary) FROM EmpBean e GROUP BY e.dept.deptnoHAVING COUNT(*) > 3 AND e.dept.deptno > 5
此查询返回多于三个职员且部门号大于五的部门的平均月薪。
可以使用不带 GROUP BY 子句的 HAVING 子句,在此情况下将整个集合视为应用 HAVING 子句的单个组。