# 创建聚合

CREATE AGGREGATE — 定义一个新的聚合函数

# 概要

CREATE [ OR REPLACE ] AGGREGATE name ( [ argmode ] [ argname ] arg_data_type [ , ... ] ) (
    SFUNC = sfunc,
    STYPE = state_data_type
    [ , SSPACE = state_data_size ]
    [ , FINALFUNC = ffunc ]
    [ , FINALFUNC_EXTRA ]
    [ , FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ]
    [ , COMBINEFUNC = combinefunc ]
    [ , SERIALFUNC = serialfunc ]
    [ , DESERIALFUNC = deserialfunc ]
    [ , INITCOND = initial_condition ]
    [ , MSFUNC = msfunc ]
    [ , MINVFUNC = minvfunc ]
    [ , MSTYPE = mstate_data_type ]
    [ , MSSPACE = mstate_data_size ]
    [ , MFINALFUNC = mffunc ]
    [ , MFINALFUNC_EXTRA ]
    [ , MFINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ]
    [ , MINITCOND = minitial_condition ]
    [ , SORTOP = sort_operator ]
    [ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ]
)

CREATE [ OR REPLACE ] 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 ]
    [ , FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ]
    [ , INITCOND = initial_condition ]
    [ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ]
    [ , HYPOTHETICAL ]
)

or the old syntax

CREATE [ OR REPLACE ] AGGREGATE name (
    BASETYPE = base_type,
    SFUNC = sfunc,
    STYPE = state_data_type
    [ , SSPACE = state_data_size ]
    [ , FINALFUNC = ffunc ]
    [ , FINALFUNC_EXTRA ]
    [ , FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ]
    [ , COMBINEFUNC = combinefunc ]
    [ , SERIALFUNC = serialfunc ]
    [ , DESERIALFUNC = deserialfunc ]
    [ , INITCOND = initial_condition ]
    [ , MSFUNC = msfunc ]
    [ , MINVFUNC = minvfunc ]
    [ , MSTYPE = mstate_data_type ]
    [ , MSSPACE = mstate_data_size ]
    [ , MFINALFUNC = mffunc ]
    [ , MFINALFUNC_EXTRA ]
    [ , MFINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ]
    [ , MINITCOND = minitial_condition ]
    [ , SORTOP = sort_operator ]
)

# 描述

创建聚合定义了一个新的聚合函数。创建或替换聚合将定义一个新的聚合函数或替换现有的定义。分布中包含一些基本和常用的聚合函数;它们记录在第 9.21 节.如果定义了新类型或需要尚未提供的聚合函数,则创建聚合可用于提供所需的功能。

替换现有定义时,不能更改参数类型、结果类型和直接参数的数量。此外,新定义必须与旧定义属于同一类型(普通集合、有序集合集合或假设集合集合)。

如果给出了模式名称(例如,创建聚合 myschema.myagg ...) 然后在指定的模式中创建聚合函数。否则,它会在当前模式中创建。

聚合函数由其名称和输入数据类型标识。如果同一模式中的两个聚合对不同的输入类型进行操作,则它们可以具有相同的名称。聚合的名称和输入数据类型也必须与同一模式中每个普通函数的名称和输入数据类型不同。这种行为与普通函数名的重载相同(参见创建函数)。

一个简单的聚合函数由一个或两个普通函数组成:状态转换函数*函数, 和一个可选的最终计算函数函数*.这些用法如下:

sfunc( internal-state, next-data-values ) ---> next-internal-state
ffunc( internal-state ) ---> aggregate-value

PostgreSQL 创建一个数据类型的临时变量*类型*保存聚合的当前内部状态。在每个输入行,计算聚合参数值,并使用当前状态值和新参数值调用状态转换函数以计算新的内部状态值。在处理完所有行之后,调用最终函数一次以计算聚合的返回值。如果没有最终函数,则按原样返回结束状态值。

聚合函数可以提供初始条件,即内部状态值的初始值。这被指定并作为类型的值存储在数据库中文本,但它必须是状态值数据类型常量的有效外部表示。如果未提供,则状态值开始为 null。

如果状态转换函数声明为“严格”,则不能使用空输入调用它。使用这样的转换函数,聚合执行的行为如下。具有任何空输入值的行将被忽略(不调用该函数并保留先前的状态值)。如果初始状态值为空,则在具有全非空输入值的第一行,第一个参数值替换状态值,并且在具有全非空输入值的每个后续行调用转换函数。这对于实现聚合很方便最大限度.请注意,此行为仅在以下情况下可用*state_data_type和第一个一样arg_data_type*.当这些类型不同时,您必须提供非空初始条件或使用非严格转换函数。

如果状态转换函数不严格,那么它将在每个输入行无条件调用,并且必须为自己处理空输入和空状态值。这允许聚合作者完全控制聚合对空值的处理。

如果最终函数声明为“strict”,则当结束状态值为 null 时不会调用它;而是会自动返回 null 结果。(当然这只是严格函数的正常行为。)在任何情况下,最终函数都可以选择返回空值。例如,最终函数平均当它看到零输入行时返回 null。

有时,将最终函数声明为不仅采用状态值,而且采用与聚合的输入值相对应的额外参数是很有用的。这样做的主要原因是最终函数是多态的,并且状态值的数据类型不足以确定结果类型。这些额外的参数总是作为 NULL 传递(因此最终函数在FINALFUNC_EXTRA选项),但它们仍然是有效的参数。例如,最终功能可以利用get_fn_expr_argtype识别当前调用中的实际参数类型。

聚合可以选择支持移动聚合模式,如中所述第 38.12.1 节.这需要指定无国界医生,MINVFUNC, 和MSTYPE参数,以及可选的微软空间,MFINAFUNC,MFINALFUNC_EXTRA,MFINALFUNC_MODIFY, 和迷你康德参数。除了MINVFUNC,这些参数的工作方式与相应的简单聚合参数一样,没有;他们定义了一个单独的聚合实现,其中包括一个反向转换函数。

语法与订购方式在参数列表中创建一种特殊类型的聚合,称为有序集聚合;或者如果假想被指定,然后一个假设集合被建造。这些聚合以依赖于顺序的方式对已排序的值组进行操作,因此输入排序顺序的规范是调用的重要部分。此外,他们可以拥有直接的参数,它们是每个聚合仅评估一次而不是每个输入行一次的参数。假设集聚合是有序集聚合的子类,其中一些直接参数需要在数量和数据类型上匹配聚合参数列。这允许将这些直接参数的值作为附加的“假设”行添加到聚合输入行的集合中。

聚合可以选择支持部分聚合,如中所述第 38.12.4 节.这需要指定组合功能范围。如果*state_data_type*是内部的,通常也适合提供串行功能解串函数参数,以便可以进行并行聚合。请注意,还必须标记聚合并行安全启用并行聚合。

行为类似的聚合体最小要么最大限度有时可以通过查看索引而不是扫描每个输入行来优化。如果此聚合可以如此优化,请通过指定排序运算符.基本要求是聚合必须产生运算符诱导的排序顺序中的第一个元素;换一种说法:

SELECT agg(col) FROM tab;

必须等同于:

SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;

进一步的假设是聚合忽略空输入,并且当且仅当没有非空输入时它才提供空结果。通常,数据类型的<运算符是正确的排序运算符最小, 和>是正确的排序运算符最大限度.请注意,除非指定的运算符是 B 树索引运算符类的“小于”或“大于”策略成员,否则优化永远不会真正生效。

为了能够创建聚合函数,您必须具有用法参数类型、状态类型和返回类型的特权,以及执行支持功能的特权。

# 参数

姓名

要创建的聚合函数的名称(可选模式限定)。

参数模式

参数的模式:要么杂音.(聚合函数不支持出去参数。)如果省略,默认为.只能标记最后一个参数杂音.

参数名称

参数的名称。这目前仅用于文档目的。如果省略,则参数没有名称。

arg_data_type

此聚合函数对其进行操作的输入数据类型。要创建一个零参数聚合函数,请编写*代替参数规范列表。(这种聚合的一个例子是数数(*).)

base_type

在旧语法中创建聚合,输入数据类型由 a 指定基本类型参数而不是写在聚合名称旁边。请注意,此语法只允许一个输入参数。要使用此语法定义零参数聚合函数,请指定基本类型作为“任何”(不是*)。无法使用旧语法定义有序集聚合。

函数

要为每个输入行调用的状态转换函数的名称。对于一个正常的*ñ-argument 聚合函数,函数一定要拿ñ+1 参数,第一个是类型state_data_type其余与聚合的声明输入数据类型匹配。该函数必须返回一个类型的值state_data_type*.此函数获取当前状态值和当前输入数据值,并返回下一个状态值。

对于有序集(包括假设集)聚合,状态转换函数仅接收当前状态值和聚合参数,而不接收直接参数。否则是一样的。

state_data_type

聚合状态值的数据类型。

state_data_size

聚合状态值的近似平均大小(以字节为单位)。如果此参数被省略或为零,则使用基于*state_data_type*.规划器使用此值来估计分组聚合查询所需的内存。

函数

在遍历所有输入行之后调用以计算聚合结果的最终函数的名称。对于普通聚合,此函数必须采用类型的单个参数*state_data_type.聚合的返回数据类型定义为本函数的返回类型。如果函数未指定,则将结束状态值用作聚合的结果,返回类型为state_data_type*.

对于有序集(包括假设集)聚合,最终函数不仅接收最终状态值,还接收所有直接参数的值。

如果FINALFUNC_EXTRA指定,则除了最终状态值和任何直接参数外,最终函数还接收与聚合的常规(聚合)参数相对应的额外 NULL 值。这主要用于在定义多态聚合时允许正确解析聚合结果类型。

FINALFUNC_MODIFY= {只读|可分享|读写}

此选项指定最终函数是否是不修改其参数的纯函数。只读表示没有;其他两个值表明它可能会改变过渡状态值。看笔记下面了解更多详细信息。默认是只读,除了有序集聚合,其默认值为读写.

组合函数

这*组合函数可以选择指定函数以允许聚合函数支持部分聚合。如果提供,则组合函数必须结合两个state_data_type值,每个值都包含对输入值的某个子集进行聚合的结果,以生成新的state_data_type表示聚合两组输入的结果。这个函数可以被认为是函数*,而不是作用于单个输入行并将其添加到正在运行的聚合状态,而是将另一个聚合状态添加到运行状态。

这*组合函数必须声明为采用两个参数state_data_type并返回一个值state_data_type*.可选地,这个函数可以是“严格的”。在这种情况下,当任一输入状态为空时,将不会调用该函数;其他状态将被视为正确结果。

对于聚合函数*state_data_type内部的, 这组合函数一定不能严格。在这种情况下组合函数*必须确保正确处理空状态,并且返回的状态正确存储在聚合内存上下文中。

串行函数

一个聚合函数,其*state_data_type内部的只有当它有一个串行函数函数,它必须将聚合状态序列化为拜茶传输到另一个进程的值。这个函数必须接受一个类型的参数内部的和返回类型拜茶.对应的反序列化函数*也是必需的。

反序列化函数

将先前序列化的聚合状态反序列化回*state_data_type*.这个函数必须接受两个类型的参数拜茶内部的,并产生类型的结果内部的.(注:第二个,内部的参数未使用,但出于类型安全原因需要。)

初始条件

状态值的初始设置。这必须是数据类型接受的形式的字符串常量*state_data_type*.如果未指定,则状态值以 null 开始。

msfunc

在移动聚合模式下为每个输入行调用的前向状态转换函数的名称。这与常规转换函数完全一样,只是它的第一个参数和结果是类型*mstate_data_type, 这可能不同于state_data_type*.

最小函数

在移动聚合模式中使用的逆状态转换函数的名称。此函数具有相同的参数和结果类型*msfunc*,但它用于从当前聚合状态中删除一个值,而不是向它添加一个值。逆向转移函数必须具有与前向状态转移函数相同的严格属性。

mstate_data_type

使用移动聚合模式时聚合状态值的数据类型。

mstate_data_size

使用移动聚合模式时聚合状态值的近似平均大小(以字节为单位)。这与*state_data_size*.

函数

使用移动聚合模式时,在遍历所有输入行后调用以计算聚合结果的最终函数的名称。这与*函数, 除了它的第一个参数的类型是mstate_data_type并且额外的虚拟参数是通过编写指定的MFINALFUNC_EXTRA.聚合结果类型由函数或者mstate_data_type*必须与聚合的常规实现所确定的匹配。

MFINALFUNC_MODIFY= {只读|可分享|读写}

这个选项就像FINALFUNC_MODIFY,但它描述了移动聚合最终函数的行为。

最小条件

使用移动聚合模式时状态值的初始设置。这与*初始条件*.

排序运算符

关联的排序运算符最小- 要么最大限度- 状聚合体。这只是一个运算符名称(可能是模式限定的)。假定运算符具有与聚合相同的输入数据类型(必须是单参数普通聚合)。

平行 ={安全的|受限制的|不安全}

的含义并行安全,并行受限, 和并行不安全与中相同创建函数.如果标记了聚合,则不会考虑进行并行化并行不安全(这是默认设置!)或并行受限.请注意,规划者不参考聚合支持功能的并行安全标记,仅参考聚合本身的标记。

假想

仅对于有序集聚合,此标志指定要根据假设集聚合的要求处理聚合参数:也就是说,最后几个直接参数必须匹配聚合的数据类型 (组内) 论点。这假想flag 对运行时行为没有影响,仅对数据类型的解析时解析和聚合参数的排序规则有影响。

的参数创建聚合可以按任何顺序编写,而不仅仅是上面说明的顺序。

# 笔记

在指定支持函数名称的参数中,您可以根据需要编写架构名称,例如SFUNC = public.sum.但是,不要在那里写参数类型——支持函数的参数类型是由其他参数确定的。

通常,PostgreSQL 函数应该是不修改其输入值的真正函数。然而,一个聚合转换函数,在聚合上下文中使用时, 被允许作弊并修改其过渡状态参数。与每次都制作新的过渡状态副本相比,这可以提供显着的性能优势。

同样,虽然通常期望聚合最终函数不会修改其输入值,但有时避免修改转换状态参数是不切实际的。这种行为必须使用FINALFUNC_MODIFY范围。这读写value 表示最终函数以未指定的方式修改转换状态。此值防止将聚合用作窗口函数,它还防止合并共享相同输入值和转换函数的聚合调用的转换状态。这可分享value 表示在 final 函数之后不能应用转换函数,但可以对结束的转换状态值执行多个 final-function 调用。此值阻止将聚合用作窗口函数,但它允许合并转换状态。(也就是说,这里感兴趣的优化不是重复应用相同的最终函数,而是将不同的最终函数应用于相同的结束转换状态值。这是允许的,只要没有标记任何最终函数读写.)如果聚合支持moving-aggregate模式,那么当聚合作为窗口函数用于具有移动帧开始的窗口(即帧开始模式不是

前无界)。从概念上讲,当它们从底部进入窗口框架时,正向转换函数将输入值添加到聚合的状态,而当它们离开顶部的框架时,反向转换函数再次将它们删除。因此,当值被删除时,它们总是按照它们添加的顺序被删除。每当调用反向转换函数时,它将因此接收最早添加但尚未删除的参数值。逆转换函数可以假设在移除最旧的行之后至少有一行将保持在当前状态。(如果不是这种情况,窗口函数机制只是开始一个新的聚合,而不是使用反向转换函数。)移动聚合模式的前向转换函数不允许返回 NULL 作为新的状态值。

如果逆转换函数返回 NULL,则这表明逆函数无法反转该特定输入的状态计算,因此将从头开始针对当前帧起始位置重新进行聚合计算。此约定允许在存在一些不切实际的不常见情况来反转运行状态值的情况下使用移动聚合模式。如果没有提供移动聚合实现,聚合仍然可以与移动帧一起使用,但是只要帧的开始移动,PostgreSQL 就会重新计算整个聚合。

注意,不管聚合是否支持移动聚合模式,PostgreSQL 都可以处理移动帧结束而无需重新计算;这是通过继续向聚合的状态添加新值来完成的。这就是为什么使用聚合作为窗口函数需要最终函数是只读的:它不能破坏聚合的状态值,这样即使在一组集合中获得聚合结果值之后,聚合也可以继续进行。帧边界。

有序集聚合的语法允许杂音为最后一个直接参数和最后一个聚合 (组内) 范围。但是,当前的实现限制了使用杂音有两种方式。首先,ordered-set 聚合只能使用可变参数“任何”,而不是其他可变参数数组类型。二、如果最后一个直接参数是可变参数“任何”,那么只能有一个聚合参数,而且它也必须是可变参数“任何”.(在系统目录中使用的表示中,这两个参数合并为一个可变参数“任何”项,因为pg_proc不能表示具有多个函数的函数杂音参数。)如果聚合是假设集聚合,则匹配的直接参数可变参数“任何”参数是假设的;任何前面的参数都表示附加的直接参数,这些参数不受限制以匹配聚合参数。

目前,有序集聚合不需要支持移动聚合模式,因为它们不能用作窗口函数。

有序集聚合当前不支持部分(包括并行)聚合。此外,它永远不会用于聚合调用,包括清楚的要么订购方式子句,因为在部分聚合期间无法支持这些语义。

# 例子

第 38.12 节.

# 兼容性

创建聚合是 PostgreSQL 语言扩展。SQL 标准不提供用户定义的聚合函数。

# 也可以看看

改变聚合,删除聚合