pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
Postgres 中的聚合函数被表示为状态值和 状态转换函数。也就是说,聚合可以按照每当处理一个输入项就被修改的状态来定义。要定义一个新的聚合函数,需要为状态值选择一种 数据类型、为状态选择一个初始值,以及一个状态转换函数。状态转换函数只是一个普通函数,也可以在聚合上下文之外使用。
实际上,为了更容易用现有函数构造有用的聚合,聚合可以有一个或两个独立的状态值、一个或两个更新这些状态值的转换函数,以及一个从最终状态值计算实际聚合结果的 最终函数。
因此最多可能涉及四种数据类型:输入数据项的类型、聚合结果的类型,以及两个状态值的类型。聚合的用户只能看到输入和结果数据类型。
有些状态转换函数需要查看每个相继的输入来计算下一个状态值,而另一些则忽略具体的输入值,只是更新自己的内部状态。(第二类最有用的例子是对输入项数量的运行计数。) Postgres 的聚合机制把聚合的 sfunc1 定义为一个同时接收旧状态值和当前输入值的函数,而 sfunc2 则是一个只接收旧状态值的函数。
如果我们定义一个只使用 sfunc1 的聚合,得到的就是一个对每个实例的属性值计算运行函数的聚合。"Sum" 就是这类聚合的一个例子。"Sum" 从零开始,总是把当前实例的值加到它的运行总和上。例如,如果我们想让 Sum 聚合作用于复数的数据类型,我们只需要该数据类型的加法函数。聚合定义是:
CREATE AGGREGATE complex_sum (
sfunc1 = complex_add,
basetype = complex,
stype1 = complex,
initcond1 = '(0,0)'
);
SELECT complex_sum(a) FROM test_complex;
+------------+
|complex_sum |
+------------+
|(34,53.9) |
+------------+
(实践中我们只会把该聚合命名为 "sum",让 Postgres 自行判断对复数列应用哪种 sum。)
如果我们只定义 sfunc2,指定的是一个对每个实例的属性值无关的运行函数计算的聚合。 "Count" 是这类聚合最常见的例子。 "Count" 从零开始,对每个实例向其运行总数加一,忽略实例的值。这里我们使用内置的 int4inc 例程为我们完成这项工作。该例程把输入加一。
CREATE AGGREGATE my_count (
sfunc2 = int4inc, -- add one
basetype = int4,
stype2 = int4,
initcond2 = '0'
);
"Average"(平均值)是一个既需要计算运行总和的函数又需要计算运行计数的函数的聚合例子。处理完所有实例后,聚合的最终答案是运行总和除以运行计数。我们使用前面用过的 int4pl 和 int4inc 例程,以及 Postgres 的整数除法例程 int4div 来计算总和除以计数。
CREATE AGGREGATE my_average (
sfunc1 = int4pl, -- sum
basetype = int4,
stype1 = int4,
sfunc2 = int4inc, -- count
stype2 = int4,
finalfunc = int4div, -- division
initcond1 = '0',
initcond2 = '0'
);
SELECT my_average(salary) as emp_average FROM EMP;
+------------+
|emp_average |
+------------+
|1640 |
+------------+
更多细节参见 PostgreSQL 用户指南 中的 CREATE AGGREGATE。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。