支持的版本: 当前 (17) / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

CREATE AGGREGATE

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 ]
)

描述

CREATE AGGREGATE 定义一个新的聚集函数。CREATE OR REPLACE AGGREGATE 将定义一个新的聚集函数或替换现有定义。一些基本的和常用的聚集函数包含在发行版中;它们在第 9.21 节中进行了文档说明。如果定义了新的类型或需要尚未提供的聚集函数,则可以使用 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 开始。

如果状态转换函数声明为严格,则不能使用 null 输入调用它。对于这样的转换函数,聚集执行的行为如下。将忽略具有任何 null 输入值的行(不会调用该函数,并保留先前状态值)。如果初始状态值为 null,则在第一个所有输入值都为非 null 的行中,第一个参数值将替换状态值,并且在每个后续的输入值都为非 null 的行中调用转换函数。这对于实现诸如 max 之类的聚集很有用。请注意,只有当 state_data_type 与第一个 arg_data_type 相同的时候,此行为才可用。当这些类型不同时,必须提供非 null 的初始条件或使用非严格的转换函数。

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

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

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

聚集可以选择支持移动聚集模式,如第 36.12.1 节中所述。这需要指定 MSFUNCMINVFUNCMSTYPE 参数,以及可选的 MSSPACEMFINALFUNCMFINALFUNC_EXTRAMFINALFUNC_MODIFYMINITCOND 参数。除了 MINVFUNC 之外,这些参数的工作方式类似于没有 M 的相应简单聚集参数;它们定义了聚集的单独实现,其中包括逆转换函数。

参数列表中带有 ORDER BY 的语法会创建一个称为有序集聚集的特殊类型的聚集;或者,如果指定了 HYPOTHETICAL,则会创建一个假设集聚集。这些聚集以依赖于顺序的方式在排序的值组上运行,因此输入排序顺序的规范是调用的重要组成部分。此外,它们可以具有直接参数,这些参数是每个聚合仅评估一次的参数,而不是每个输入行评估一次。假设集聚集是有序集聚集的子类,其中一些直接参数在数量和数据类型上必须与聚合参数列匹配。这允许将这些直接参数的值添加到聚合输入行的集合中,作为额外的假设行。

聚集可以选择支持部分聚集,如第 36.12.4 节中所述。这需要指定 COMBINEFUNC 参数。如果 state_data_typeinternal,则通常也适合提供 SERIALFUNCDESERIALFUNC 参数,以便可以进行并行聚集。请注意,还必须将聚集标记为 PARALLEL SAFE 才能启用并行聚集。

行为类似于 MINMAX 的聚集有时可以通过查看索引而不是扫描每个输入行来优化。如果可以通过这种方式优化此聚集,请通过指定排序运算符来指示它。基本要求是聚集必须产生由运算符引起的排序中的第一个元素;换句话说

SELECT agg(col) FROM tab;

必须等效于

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

进一步的假设是,聚集忽略 null 输入,并且当且仅当没有非 null 输入时,它才会传递 null 结果。通常,数据类型的 < 运算符是 MIN 的适当排序运算符,而 >MAX 的适当排序运算符。请注意,除非指定的运算符是 B 树索引运算符类的小于大于策略成员,否则优化实际上永远不会生效。

要创建聚合函数,您必须拥有参数类型、状态类型和返回类型的 USAGE 权限,以及对支持函数的 EXECUTE 权限。

参数

name

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

argmode

参数的模式:INVARIADIC。(聚合函数不支持 OUT 参数。)如果省略,则默认为 IN。只有最后一个参数可以标记为 VARIADIC

argname

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

arg_data_type

此聚合函数在其上运行的输入数据类型。要创建零参数聚合函数,请使用 * 代替参数规范列表。(例如,count(*) 就是这样的聚合函数。)

base_type

CREATE AGGREGATE 的旧语法中,输入数据类型由 basetype 参数指定,而不是写在聚合名称旁边。请注意,此语法只允许一个输入参数。要使用此语法定义零参数聚合函数,请将 basetype 指定为 "ANY"(而不是 *)。有序集聚合不能使用旧语法定义。

sfunc

为每个输入行调用的状态转换函数的名称。对于普通的 N 参数聚合函数,sfunc 必须接受 N+1 个参数,第一个参数的类型为 state_data_type,其余参数与聚合的已声明输入数据类型匹配。该函数必须返回 state_data_type 类型的值。此函数接受当前状态值和当前输入数据值,并返回下一个状态值。

对于有序集(包括假设集)聚合,状态转换函数仅接收当前状态值和聚合的参数,而不是直接参数。其他方面相同。

state_data_type

聚合状态值的数据类型。

state_data_size

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

ffunc

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

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

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

FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE }

此选项指定最终函数是否是不修改其参数的纯函数。READ_ONLY 表示它不修改;其他两个值表示它可能会更改转换状态值。有关更多详细信息,请参阅下面的注释。默认值为 READ_ONLY,但有序集聚合除外,其默认值为 READ_WRITE

combinefunc

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

combinefunc 必须声明为接受两个 state_data_type 参数并返回 state_data_type 类型的值。可选地,此函数可以是strict。在这种情况下,当任何一个输入状态为空时,该函数将不会被调用;另一个状态将被视为正确的结果。

对于 state_data_typeinternal 的聚合函数,combinefunc 不得是 strict 的。在这种情况下,combinefunc 必须确保正确处理空状态,并且将返回的状态正确存储在聚合内存上下文中。

serialfunc

如果聚合函数的 state_data_typeinternal,则只有在具有 serialfunc 函数的情况下才能参与并行聚合,该函数必须将聚合状态序列化为 bytea 值,以便传输到另一个进程。此函数必须接受类型为 internal 的单个参数并返回类型 bytea。还需要相应的 deserialfunc

deserialfunc

将先前序列化的聚合状态反序列化回 state_data_type。此函数必须接受两个类型为 byteainternal 的参数,并生成类型为 internal 的结果。(注意:第二个 internal 参数未使用,但为了类型安全而需要。)

initial_condition

状态值的初始设置。这必须是一个字符串常量,其形式为 state_data_type 数据类型所接受的形式。如果未指定,则状态值从空开始。

msfunc

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

minvfunc

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

mstate_data_type

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

mstate_data_size

当使用前移聚合模式时,聚合的状态值的近似平均大小(以字节为单位)。这与 state_data_size 的工作方式相同。

mffunc

当使用前移聚合模式时,在遍历所有输入行后,调用以计算聚合结果的最终函数的名称。这与 ffunc 的工作方式相同,只是它的第一个参数的类型为 mstate_data_type,并且通过编写 MFINALFUNC_EXTRA 指定额外的虚拟参数。由 mffuncmstate_data_type 确定的聚合结果类型必须与聚合的常规实现所确定的类型匹配。

MFINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE }

此选项类似于 FINALFUNC_MODIFY,但它描述了前移聚合最终函数的行为。

minitial_condition

当使用前移聚合模式时,状态值的初始设置。这与 initial_condition 的工作方式相同。

sort_operator

类似于 MINMAX 的聚合的相关排序运算符。这只是一个运算符名称(可能包含模式限定)。假定运算符具有与聚合相同的输入数据类型(必须是单参数的普通聚合)。

PARALLEL = { SAFE | RESTRICTED | UNSAFE }

PARALLEL SAFEPARALLEL RESTRICTEDPARALLEL UNSAFE 的含义与 CREATE FUNCTION 中相同。如果聚合标记为 PARALLEL UNSAFE(这是默认值!)或 PARALLEL RESTRICTED,则不会考虑将其用于并行化。请注意,计划器不会咨询聚合的支持函数的并行安全标记,而只会咨询聚合本身的标记。

HYPOTHETICAL

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

CREATE AGGREGATE 的参数可以按任何顺序编写,而不仅仅是上面说明的顺序。

注释

在指定支持函数名称的参数中,如果需要,您可以写入模式名称,例如 SFUNC = public.sum。但是,不要在那里写入参数类型 - 支持函数的参数类型是从其他参数确定的。

通常,PostgreSQL 函数应为不修改其输入值的纯函数。但是,聚合转换函数在聚合的上下文中使用时,可以作弊并就地修改其转换状态参数。与每次都制作转换状态的新副本相比,这可以提供显著的性能优势。

同样地,虽然通常期望聚合的最终函数不会修改其输入值,但有时避免修改转换状态参数是不切实际的。 必须使用 FINALFUNC_MODIFY 参数来声明这种行为。READ_WRITE 值表示最终函数以未指定的方式修改转换状态。此值会阻止将聚合用作窗口函数,并且还会阻止合并共享相同输入值和转换函数的聚合调用的转换状态。SHAREABLE 值表示在最终函数之后不能应用转换函数,但可以对结束转换状态值执行多个最终函数调用。 此值会阻止将聚合用作窗口函数,但允许合并转换状态。(也就是说,此处关注的优化不是重复应用相同的最终函数,而是对相同的结束转换状态值应用不同的最终函数。 只要没有任何最终函数被标记为 READ_WRITE,这是允许的。)

如果聚合支持移动聚合模式,则当聚合用作具有移动帧起始位置的窗口的窗口函数时(即,帧起始模式不是 UNBOUNDED PRECEDING 时),它将提高计算效率。 从概念上讲,前向转换函数会在输入值从底部进入窗口帧时将其添加到聚合的状态,而逆向转换函数会在它们从顶部离开帧时再次将其删除。 因此,当值被删除时,它们总是以添加时的相同顺序被删除。 每当调用逆向转换函数时,它都会接收最早添加但尚未删除的参数值。 逆向转换函数可以假设在删除最早的行之后,当前状态中至少会保留一行。(如果情况并非如此,窗口函数机制只会启动新的聚合,而不是使用逆向转换函数。)

不允许移动聚合模式的前向转换函数返回 NULL 作为新的状态值。 如果逆向转换函数返回 NULL,则表示逆向函数无法反转此特定输入的转换状态计算,因此将从当前帧起始位置重新执行聚合计算。 此约定允许在某些不常见的情况下难以从运行状态值中反转时使用移动聚合模式。

如果没有提供移动聚合实现,则仍然可以将聚合与移动帧一起使用,但是当帧的起始位置移动时,PostgreSQL 将重新计算整个聚合。请注意,无论聚合是否支持移动聚合模式,PostgreSQL 都可以处理移动的帧结束位置而无需重新计算;这是通过继续将新值添加到聚合状态来实现的。 这就是为什么使用聚合作为窗口函数要求最终函数是只读的原因:它不得损坏聚合的状态值,以便即使在获得一组帧边界的聚合结果值后,也可以继续聚合。

有序集合聚合的语法允许为最后一个直接参数和最后一个聚合的(WITHIN GROUP)参数指定 VARIADIC。 但是,当前的实现以两种方式限制了 VARIADIC 的使用。 首先,有序集合聚合只能使用 VARIADIC "any",而不能使用其他可变数组类型。 其次,如果最后一个直接参数是 VARIADIC "any",则只能有一个聚合参数,并且它也必须是 VARIADIC "any"。(在系统目录中使用的表示形式中,这两个参数合并为一个 VARIADIC "any" 项,因为 pg_proc 不能表示具有多个 VARIADIC 参数的函数。)如果聚合是假设集合聚合,则与 VARIADIC "any" 参数匹配的直接参数是假设的参数; 任何前面的参数都表示不限制为与聚合参数匹配的附加直接参数。

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

目前,有序集合聚合不支持部分(包括并行)聚合。 此外,它永远不会用于包含 DISTINCTORDER BY 子句的聚合调用,因为在部分聚合期间无法支持这些语义。

示例

请参阅第 36.12 节

兼容性

CREATE AGGREGATEPostgreSQL 语言扩展。 SQL 标准不提供用户定义的聚合函数。

提交更正

如果您在文档中看到任何不正确的内容、与特定功能的体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。