CREATE AGGREGATE name ( [ argmode ] [ argname ] arg_data_type [ , ... ] ) (
SFUNC = sfunc,
STYPE = state_data_type
[ , SSPACE = state_data_size ]
[ , FINALFUNC = ffunc ]
[ , FINALFUNC_EXTRA ]
[ , INITCOND = initial_condition ]
[ , MSFUNC = msfunc ]
[ , MINVFUNC = minvfunc ]
[ , MSTYPE = mstate_data_type ]
[ , MSSPACE = mstate_data_size ]
[ , MFINALFUNC = mffunc ]
[ , MFINALFUNC_EXTRA ]
[ , MINITCOND = minitial_condition ]
[ , SORTOP = sort_operator ]
)
CREATE AGGREGATE name ( [ [ argmode ] [ argname ] arg_data_type [ , ... ] ]
ORDER BY [ argmode ] [ argname ] arg_data_type [ , ... ] ) (
SFUNC = sfunc,
STYPE = state_data_type
[ , SSPACE = state_data_size ]
[ , FINALFUNC = ffunc ]
[ , FINALFUNC_EXTRA ]
[ , INITCOND = initial_condition ]
[ , HYPOTHETICAL ]
)
或者是老的语法
CREATE AGGREGATE name (
BASETYPE = base_type,
SFUNC = sfunc,
STYPE = state_data_type
[ , SSPACE = state_data_size ]
[ , FINALFUNC = ffunc ]
[ , FINALFUNC_EXTRA ]
[ , INITCOND = initial_condition ]
[ , MSFUNC = msfunc ]
[ , MINVFUNC = minvfunc ]
[ , MSTYPE = mstate_data_type ]
[ , MSSPACE = mstate_data_size ]
[ , MFINALFUNC = mffunc ]
[ , MFINALFUNC_EXTRA ]
[ , MINITCOND = minitial_condition ]
[ , SORTOP = sort_operator ]
)
CREATE AGGREGATE定义一个新的聚合函数。 一些常用的聚合函数已经包含在基础软件包里了;在第 9.20 节里有文档说明。 如果你需要定义一个新类型或需要一个还没有提供的聚合函数,这时CREATE AGGREGATE便可派上用场。
如果给出了一个模式的名字(比如CREATE AGGREGATE myschema.myagg ...),那么该聚合函数是在指定模式中创建的。 否则它是在当前模式中创建的。
一个聚合函数是用它的名字和输入数据类型来标识的。 同一模式中如果两个聚合处理的输入数据不同,它们可以有相同的名字。 一个聚合函数的输入数据类型必须和所有同一模式中的普通函数的名字和输入类型不同。 这个行为和重载普通函数名相同(参阅CREATE FUNCTION)。
一个简单的聚合函数是用一个或两个普通函数组成的:一个状态转换函数sfunc和一个可选的最终计算函数ffunc。 它们是这样使用的:
sfunc( internal-state, next-data-values ) ---> next-internal-state ffunc( internal-state ) ---> aggregate-value
PostgreSQL创建一个类型为stype的临时变量。 它保存这个聚合的当前内部状态。对于每个输入数据条目,都调用状态转换函数计算内部状态值的新数值。 在处理完所有数据后,调用一次最终处理函数以计算聚合的返回值。如果没有最终处理函数, 则将最后的状态值当做返回值。
一个聚合函数还可能提供一个初始条件,也就是内部状态值的初始值。 这个值是作为一个类型为text的字段存储在数据库里的,不过它们必须是状态值数据类型的合法的外部 表现形式的常量。 如果没有提供状态,那么状态值初始化为 NULL 。
如果该状态转换函数被定义为"strict",那么就不能用 NULL 输入调用它。
此时, 聚合的执行如下所述。带有任何 NULL 输入值的行将被忽略(不调用此函数并且保留前一个状态值)。
如果初始状态值是 NULL ,那么在第一个含有非 NULL 值的行上,
使用第一个参数值替换状态值,然后状态转换函数在随后每个含有非 NULL 值的行上调用。
这样做让比较容易实现像max
这样的聚合。
请注意这种行为只是当state_data_type
与第一个arg_data_type相同的时候才表现出来。
如果这些类型不同,你必须提供一个非 NULL 的初始条件或者使用一个非"strict"的状态转换函数。
如果状态转换函数不是严格(strict)的,那么它将无条件地在每个输入行上调用, 并且必须自行处理空输入和空状态值,这样就允许聚合的作者对聚合中的空值有完全的控制。
如果最终转换函数定义为"strict",那么如果最终状态值是NULL 时就不会调用它;
而是自动输出一个 NULL 结果。(这才是 strict 函数的正常特征。)
不管是哪种情况,最终处理函数 可以自由选择是否返回 NULL 。
比如,avg
的最终处理函数在零输入记录时就会返回 NULL 。
有时声明最终函数不只是接受状态值是有用的,但是需要额外的参数对应到聚合的输入值。
这样做的主要原因是,如果最终函数是多态的并且状态值的数据类型不足以确定结果类型。
这些额外的参数总是作为NULL传递(因此最终函数在使用了FINALFUNC_EXTRA
选项时必须是非严格的),虽然如此,它们也是有效的参数。
最终函数可以,例如利用get_fn_expr_argtype
确定当前调用中的实际参数类型。
一个聚合可以选择支持moving-aggregate mode, 就像第 35.10.1 节中描述的那样。 这需要声明MSFUNC、MINVFUNC和MSTYPE参数, 可选的声明MSPACE、MFINALFUNC、MFINALFUNC_EXTRA 和MINITCOND参数。除了MINVFUNC, 这些参数和对应的简单的不带有M的聚合参数类似; 它们定义一个聚合的单独实现,包括反向转换函数。
在参数列表中带有ORDER BY的语法创建了一个名为 顺序集聚合的特殊聚合类型;或者如果声明了 HYPOTHETICAL,那么创建了一个假想集聚合。 这些聚合以顺序依赖的方式在存储的值组上操作,所以输入排序顺序的说明是调用的一个重要部分。 另外,它们可以有直接参数,这些参数仅在每个聚合中计算一次, 而不是在每个输入行中计算一次。假想集聚合是顺序集聚合的一个子类, 其中的一些直接参数需要在数量数据类型和聚合的参数字段上匹配。 这允许这些直接参数的值作为额外的"假想" 行添加到聚合输入行的集合。
行为类似MIN
或MAX
的聚合有时候可以优化为使用索引,而不用扫描 每个输入行。
如果这个聚合可以如此优化,则用一个排序操作符标识它。
这里基本的要求是聚合 必须以操作符归纳出来的排序顺序生成第一个元素;换句话说:
SELECT agg(col) FROM tab;
必须等于:
SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
更多的假设是聚合忽略 NULL 输入,并且只有在输入没有非空数值的时候,它才生成NULL结果。
通常,数据类型的 < 操作符是MIN
的适用排序操作符,而 > 是MAX
的适用操作符。
请注意,除非声明的操作符是 B-tree 索引操作符类的"小于"或者"大于"策略号, 否则这种优化将不会生效。
要创建聚合函数,你必须具有相关参数类型、状态类型和返回类型的USAGE 权限,也必须具有转换函数和最终函数的EXECUTE权限。
要创建的聚合函数名(可以有模式修饰) 。
一个参数的模式:IN或VARIADIC。 (聚合函数不支持OUT参数。)如果省略,缺省是IN。 只有最后一个参数可以被标记为VARIADIC。
参数的名字。目前仅对文档有用。如果省略,该参数没有名字。
该聚合函数要处理的输入数据类型。要创建一个零参数聚合函数,可以使用*代替参数说明列表。
(count(*)
就是这种聚合函数的一个实例。 )
在以前的CREATE AGGREGATE语法中,输入数据类型是通过basetype参数指定的,而不是写在聚合的名称之后。 需要注意的是这种以前语法仅允许一个输入参数。要用这个语法定义一个零参数聚合函数, 可以将basetype指定为"ANY"(而不是*)。 不能用老的语法定义顺序集聚合。
将在每一个输入行上调用的状态转换函数的名称。 对于有N个参数的聚合函数,sfunc必须有 +1 个参数,其中的第一个参数类型为state_data_type,其余的匹配已声明的输入数据类型。 函数必须返回一个state_data_type类型的值。 这个函数接受当前状态值和当前输入数据,并返回下个状态值。
对于顺序集聚合(包括假想集),状态转换函数仅接受当前状态值和聚合的参数, 不接受直接参数。否则它们就相同了。 For ordered-set (including hypothetical-set) aggregates, the state transition function receives only the current state value and the aggregated arguments, not the direct arguments. Otherwise it is the same.
聚合的状态值的数据类型。
聚合的状态值的大约平均大小(以字节计)。如果省略了这个参数或者参数值为0, 则使用基于state_data_type的缺省估计。 规划器使用这个值估计分组的聚合查询所需的内存。 只有预计哈希表适合work_mem时, 规划器才为这样一个查询考虑使用哈希聚合;因此, 这个参数值较大的话,会妨碍使用哈希聚合。
在转换完所有输入行后调用的最终处理函数,它计算聚合的结果。对于一个普通聚合, 此函数必须接受一个类型为state_data_type的参数。 聚合的输出数据类型被定义为此函数的返回类型。 如果没有声明ffunc则使用聚合结果的状态值作为聚合的结果,且输出类型为state_data_type。
对于顺序集(包括假设集)聚合,最终函数不只是接受最终的状态值, 也接受所有直接参数的值。
如果声明了FINALFUNC_EXTRA,那么除了最终状态值和任何直接参数外, 最终函数还接受额外的NULL值对应于该聚合的普通(聚合的)参数。 这在定义多态聚合函数时,对于正确的解析聚合的结果类型很有帮助。
状态值的初始设置(值)。 它必须是一个state_data_type类型可以接受的文本常量值。 如果没有声明,状态值初始为 NULL 。
moving-aggregate模式下每个输入行调用的正向状态转换函数的名字。 这恰好类似于普通转换函数,除了它的第一个参数和结果是 mstate_data_type类型的,与 state_data_type类型不同。
moving-aggregate模式下使用的反向状态转换函数的名字。 这个函数有着和msfunc一样的参数和结果类型, 但是它是用来从当前聚合状态中移除一个值的,而不是添加一个值。 该反向转换函数必须和正向状态转换函数拥有严格相同的属性。
当使用moving-aggregate模式时,聚合的状态值的数据类型。
当使用moving-aggregate模式时,聚合的状态值的大约平均大小(以字节计)。 这和state_data_size相同。
使用moving-aggregate模式时,在所有输入行被转换后, 调用来计算聚合的结果的最终函数的名字。 这和ffunc相同,除了它的第一个参数的类型是 mstate_data_type和额外的空变量是通过MFINALFUNC_EXTRA 声明的。该聚合的结果类型视mffunc而定, 或者mstate_data_type必须匹配视该聚合的普通实现而定。
当使用moving-aggregate模式时,状态值的内部设置。 这和initial_condition相同。
用于MIN
或MAX
类型聚合的排序操作符。
这个只是一个操作符名 (可以有模式修饰)。
这个操作符假设接受和聚合一样的输入数据类型(它必须是一个单参数普通聚合)。
仅对于顺序集聚合,这个标志声明了根据假想集聚合的需求要被处理的聚合参数: 也就是,最后几个直接参数必须匹配聚合的(WITHIN GROUP) 参数的数据类型。HYPOTHETICAL标志对运行时行为没有影响, 只对分析时辨识数据类型和聚合的参数的排序有影响。
CREATE AGGREGATE的参数可以以任何顺序书写,而不只是上面显示的顺序。
在声明支持函数名的参数中,如果需要,你可以写入模式名,例如 SFUNC = public.sum。在这里不要写参数类型, 不过 — 支持的函数的参数类型是由其他参数决定的。
如果一个聚合支持moving-aggregate模式, 那么当聚合用作一个带有移动帧起始的窗口的窗口函数时, 它将提升计算效率(也就是帧起始模式,而不是UNBOUNDED PRECEDING)。 从概念上讲,当从底部进入窗口帧时,正向转换函数添加输入值到聚合的状态, 当从顶部离开帧时反向转换函数删除它们。所以,当值被移除时, 它们总是以它们添加的顺序移除。当调用反向转换函数时, 它将因此收到最早添加但是还未删除的参数值。 反向转换函数可以假设在它删除最老的行之后至少还有一行保留在当前的状态中。 (当不是这种情况是,窗口函数机制只是启动一个新的聚合, 而不是使用反向转换函数。)
正向转换函数在moving-aggregate模式下是不允许返回NULL作为新的状态值的。 如果反向转换函数返回了NULL,这将被当做反向函数不能为这个特殊输入解析状态计算的指示, 并且因此聚合计算将从当前帧起始位置重做。 这个约定允许moving-aggregate模式用在一些不常见的不切实际的逆转运行状态值的情况下。
如果没有应用moving-aggregate实现,聚合仍然可以使用移动帧, 但是PostgreSQL将在帧起始位置移动时重新计算整个聚合。 请注意,不管聚合是否支持moving-aggregate模式, PostgreSQL都可以处理移动帧结束而不用重新计算, 这是通过持续添加新的值到聚合的状态做到的。它假设最终函数不毁坏聚合的状态值, 这样聚合可以持续,即使是在已经获得了一组帧的边界的聚合结果值之后。
顺序集聚合的语法允许为最后的直接参数和最后聚合的(WITHIN GROUP) 参数声明VARIADIC。不过,当前实现以两种方式约束使用 VARIADIC。第一,顺序集聚合只能使用VARIADIC "any", 不能使用其他variadic数组类型。第二,如果最后的直接参数是 VARIADIC "any",那么只能有一个聚合的参数并且它必须也是 VARIADIC "any"。(在系统目录中使用的表示,这两个参数合并为一个 VARIADIC "any"项,因为pg_proc 不能代表带有多于一个VARIADIC参数的函数。) 如果该聚合是一个假想集聚合,那么匹配VARIADIC "any" 参数的那个直接参数是假想的那一个; 任何之前的参数表示不必匹配聚合的参数的额外直接参数。
目前,顺序集聚合不需要支持moving-aggregate模式, 因为它们不能用作窗口函数。