Aggregate functions in <productname>PostgreSQL</productname> are defined in terms of <firstterm>state values</firstterm> and <firstterm>state transition functions</firstterm>. That is, an aggregate operates using a state value that is updated as each successive input row is processed. To define a new aggregate function, one selects a data type for the state value, an initial value for the state, and a state transition function. The state transition function takes the previous state value and the aggregate's input value(s) for the current row, and returns a new state value. A <firstterm>final function</firstterm> can also be specified, in case the desired result of the aggregate is different from the data that needs to be kept in the running state value. The final function takes the ending state value and returns whatever is wanted as the aggregate result. In principle, the transition and final functions are just ordinary functions that could also be used outside the context of the aggregate. (In practice, it's often helpful for performance reasons to create specialized transition functions that can only work when called as part of an aggregate.) PostgreSQLにおける集約関数は、状態値と状態遷移関数で定義されています。 つまり集約は、入力行を順次処理して更新される状態値を使用することで動作します。 新しい集約関数を定義するためには、状態値のデータ型、初期状態値、そして状態遷移関数のデータ型を選択します。 状態遷移関数は、前の状態値と現在行の集約のための入力値(複数可)を取り、新たな状態値を返します。 実行中に保持する状態値と求めている集約の結果のデータが違う場合は、最終関数を指定することもできます。 最終関数は、最後の状態値を取り、そして集約の結果として望まれているものを返します。 原則として、遷移関数と最終関数は、通常の関数であり集約以外の状況でも使用することができます。 (実際には、集約の一部として呼び出されて動作する専用の遷移関数を作成することは、多くの場合パフォーマンス上の理由から役立ちます。)
Thus, in addition to the argument and result data types seen by a user of the aggregate, there is an internal state-value data type that might be different from both the argument and result types. したがって、集約のユーザに見える引数と結果のデータ型に加え、引数と結果の型のどちらとも違う可能性がある内部状態値のデータ型があります。
If we define an aggregate that does not use a final function,
we have an aggregate that computes a running function of
the column values from each row. <function>sum</function> is an
example of this kind of aggregate. <function>sum</function> starts at
zero and always adds the current row's value to
its running total. For example, if we want to make a <function>sum</function>
aggregate to work on a data type for complex numbers,
we only need the addition function for that data type.
The aggregate definition would be:
最終関数を使わない集約を定義した場合は、列の値を行ごとに計算する関数を実行することで集約ができます。
sum
はそのような集約の一例です。
sum
は0から始まり、常に現在の行の値をその時点までの総和に追加します。
例えば、もしsum
集約を複素数(complex)のデータ型で動作するようにしたければ、そのデータ型の加算関数だけが必要になります。
集約の定義は以下のようになります。
CREATE AGGREGATE sum (complex) ( sfunc = complex_add, stype = complex, initcond = '(0,0)' );
which we might use like this: これは以下のように使用します。
SELECT sum(a) FROM test_complex; sum ----------- (34,53.9)
(Notice that we are relying on function overloading: there is more than
one aggregate named <function>sum</function>, but
<productname>PostgreSQL</productname> can figure out which kind
of sum applies to a column of type <type>complex</type>.)
(関数のオーバーロード機能に依存していることに注意してください。
sum
という名前の集約関数は複数存在しますが、PostgreSQLは列のcomplex
型に適用できるsum関数を見つけ出すことができます。)
The above definition of <function>sum</function> will return zero
(the initial state value) if there are no nonnull input values.
Perhaps we want to return null in that case instead — the SQL standard
expects <function>sum</function> to behave that way. We can do this simply by
omitting the <literal>initcond</literal> phrase, so that the initial state
value is null. Ordinarily this would mean that the <literal>sfunc</literal>
would need to check for a null state-value input. But for
<function>sum</function> and some other simple aggregates like
<function>max</function> and <function>min</function>,
it is sufficient to insert the first nonnull input value into
the state variable and then start applying the transition function
at the second nonnull input value. <productname>PostgreSQL</productname>
will do that automatically if the initial state value is null and
the transition function is marked <quote>strict</quote> (i.e., not to be called
for null inputs).
上記のsum
の定義は、もし非NULLの入力値がなければ0(初期状態)を返します。
本来はこの場合NULLを返したいのではないかと思いますし、標準SQLではsum
がそのように動作することを期待しています。
そうするためには、単にinitcond
句を省略すれば、初期状態がNULLになります。
通常このことは、sfunc
がNULL状態の入力をチェックする必要があることを意味します。
しかしsum
や、その他max
、min
のような単純な集約にとっては、状態変数に最初の非NULL入力値を挿入し、
2番目の非NULL入力値で状態遷移関数の適用を開始すれば十分です。
PostgreSQLは、もし初期状態がNULLで状態遷移関数が「strict(厳密)」と宣言されている場合、自動的にそのように動作します(つまりNULL入力では呼び出されないようになります)。
Another bit of default behavior for a <quote>strict</quote> transition function is that the previous state value is retained unchanged whenever a null input value is encountered. Thus, null values are ignored. If you need some other behavior for null inputs, do not declare your transition function as strict; instead code it to test for null inputs and do whatever is needed. もう1つの「strict」な状態遷移関数のデフォルト動作としては、NULL入力値が現れると前の状態値が変わらずに維持されるということがあります。 したがって、NULL値は無視されます。 もしNULL入力に対し他の動作が必要な場合は、状態遷移関数をstrict宣言しないようにします。その代わりにNULL入力の検査をおこなうようにコーディングし、必要なことをすればよいのです。
<function>avg</function> (average) is a more complex example of an aggregate.
It requires
two pieces of running state: the sum of the inputs and the count
of the number of inputs. The final result is obtained by dividing
these quantities. Average is typically implemented by using an
array as the state value. For example,
the built-in implementation of <function>avg(float8)</function>
looks like:
avg
(平均値計算)はもっと複雑な集約の一例です。
それには2つの変動する状態が必要になります。入力の合計と入力数のカウントです。
最終的な結果はこれらの値を割算することによって得られます。
平均値計算は配列を状態遷移値として使う典型的な実装です。
例えば、avg(float8)
の組み込みの実装は以下のようになっています。
CREATE AGGREGATE avg (float8) ( sfunc = float8_accum, stype = float8[], finalfunc = float8_avg, initcond = '{0,0,0}' );
<function>float8_accum</function> requires a three-element array, not just
two elements, because it accumulates the sum of squares as well as
the sum and count of the inputs. This is so that it can be used for
some other aggregates as well as <function>avg</function>.
float8_accum
は、入力の総和と個数だけではなく二乗和も蓄積しますので、2要素ではなく、3要素の配列を必要とします。
それは、avg
以外の他の集約でも使用できるようにするためです。
Aggregate function calls in SQL allow <literal>DISTINCT</literal>
and <literal>ORDER BY</literal> options that control which rows are fed
to the aggregate's transition function and in what order. These
options are implemented behind the scenes and are not the concern
of the aggregate's support functions.
SQLの集約関数はオプションによりDISTINCT
とORDER BY
を許可します。それは集約の遷移関数に渡される行や順序を制御します。これらのオプションは裏側で実装されるので、集約のサポート関数が気にする必要はありません。
For further details see the <xref linkend="sql-createaggregate"/> command. さらなる詳細については、CREATE AGGREGATEコマンドを参照してください。
Aggregate functions can optionally support <firstterm>moving-aggregate
mode</firstterm>, which allows substantially faster execution of aggregate
functions within windows with moving frame starting points.
(See <xref linkend="tutorial-window"/>
and <xref linkend="syntax-window-functions"/> for information about use of
aggregate functions as window functions.)
The basic idea is that in addition to a normal <quote>forward</quote>
transition function, the aggregate provides an <firstterm>inverse
transition function</firstterm>, which allows rows to be removed from the
aggregate's running state value when they exit the window frame.
For example a <function>sum</function> aggregate, which uses addition as the
forward transition function, would use subtraction as the inverse
transition function. Without an inverse transition function, the window
function mechanism must recalculate the aggregate from scratch each time
the frame starting point moves, resulting in run time proportional to the
number of input rows times the average frame length. With an inverse
transition function, the run time is only proportional to the number of
input rows.
集約関数は、移動集約モードをオプションでサポートします。それは、ウィンドウ内のフレーム開始点を移動することで、集約関数の実行を大幅に高速にすることができます。
(集約関数としてのウィンドウ関数の使用に関する情報は3.5と 4.2.8 を参照してください。)
基本的な考え方は、通常の「順方向」の遷移関数に加えて、集約は逆方向遷移関数を提供します。これによりウィンドウフレームが終了した時点で、集約の実行中の状態値から行を除外することが可能になります。
例えば、sum
集約では、順方向遷移関数として加算を使用しており、逆方向遷移関数として減算を使用します。
逆方向遷移関数を持たないとウィンドウ関数は、フレームの開始点に移動するたびに一から集約を再計算しなければなりません。
その実行時間は、入力行の数のフレーム長の平均回数倍に比例します。
逆遷移関数を使用すると実行時間は、入力行の数にのみ比例します。
The inverse transition function is passed the current state value and the aggregate input value(s) for the earliest row included in the current state. It must reconstruct what the state value would have been if the given input row had never been aggregated, but only the rows following it. This sometimes requires that the forward transition function keep more state than is needed for plain aggregation mode. Therefore, the moving-aggregate mode uses a completely separate implementation from the plain mode: it has its own state data type, its own forward transition function, and its own final function if needed. These can be the same as the plain mode's data type and functions, if there is no need for extra state. 逆遷移関数には、現在の状態値と現在の状態が含まれる最も古い行の集約入力値(複数可)を渡されます。 与えられた入力行が集約されていなかった場合は、それに続く行のみ状態値を再構築する必要があります。 これは時々、順方向遷移関数は通常の集約モードよりも必要な状態を持つことが必要になります。 そのため、移動集約モードは、通常のモードから完全に分離した実装を使用します。 必要に応じて、独自の状態データ型、独自の順方向遷移関数、及びそれ独自の最終関数を持ちます。 これらは必要がない場合、通常モードのデータ型および関数と同じでも構いません。
As an example, we could extend the <function>sum</function> aggregate given above
to support moving-aggregate mode like this:
例として、移動集約モードをサポートするために、以下のようにsum
集約を拡張できます。
CREATE AGGREGATE sum (complex) ( sfunc = complex_add, stype = complex, initcond = '(0,0)', msfunc = complex_add, minvfunc = complex_sub, mstype = complex, minitcond = '(0,0)' );
The parameters whose names begin with <literal>m</literal> define the
moving-aggregate implementation. Except for the inverse transition
function <literal>minvfunc</literal>, they correspond to the plain-aggregate
parameters without <literal>m</literal>.
m
で始まる名前のパラメータは、移動集約の実装を定義します。
逆遷移関数minvfunc
以外はm
のない通常の集約パラメータに対応しています。
The forward transition function for moving-aggregate mode is not allowed
to return null as the new state value. If the inverse transition
function returns null, this is taken as an indication that the inverse
function cannot reverse the state calculation for this particular input,
and so the aggregate calculation will be redone from scratch for the
current frame starting position. This convention allows moving-aggregate
mode to be used in situations where there are some infrequent cases that
are impractical to reverse out of the running state value. The inverse
transition function can <quote>punt</quote> on these cases, and yet still come
out ahead so long as it can work for most cases. As an example, an
aggregate working with floating-point numbers might choose to punt when
a <literal>NaN</literal> (not a number) input has to be removed from the running
state value.
移動集約モードのための順方向遷移関数は、新しい状態値としてnullを返すことが許されていません。
逆遷移関数がnullを返した場合、関数はこの特定の入力に対して状態計算を逆にできないことを示すものと考えます。そのような集約計算は、現在のフレーム開始位置からやり直すことになります。
この規則は、実行中の状態値から逆転することが現実的でないような、まれなケースで使用することが出来ます。
逆遷移関数はこれらのケースで「諦め」ますが、大部分のケースで動作することが出来ます。
例として、浮動小数点数を扱う集約は、NaN
(非数)の入力が実行されている状態値から除去されなければならない時に諦めることを選択するかもしれません。
When writing moving-aggregate support functions, it is important to be
sure that the inverse transition function can reconstruct the correct
state value exactly. Otherwise there might be user-visible differences
in results depending on whether the moving-aggregate mode is used.
An example of an aggregate for which adding an inverse transition
function seems easy at first, yet where this requirement cannot be met
is <function>sum</function> over <type>float4</type> or <type>float8</type> inputs. A
naive declaration of <function>sum(<type>float8</type>)</function> could be
移動集約サポート関数を記述する際には、逆遷移関数が正しい状態値を正確に再構築できていることを確認することが重要です。
それ以外の場合は、移動集約モードが使用されているかどうかに応じてユーザに見える結果に違いがあるかもしれません。
逆遷移関数を追加する最初の簡単な例は、要件を満たせていないfloat4
やfloat8
入力のsum
です。
稚拙なsum(
の宣言です。
float8
)
CREATE AGGREGATE unsafe_sum (float8) ( stype = float8, sfunc = float8pl, mstype = float8, msfunc = float8pl, minvfunc = float8mi );
This aggregate, however, can give wildly different results than it would have without the inverse transition function. For example, consider しかし、この集約は、逆遷移関数を持たない場合と比較すると著しく異なる結果になります。 例を考えます。
SELECT unsafe_sum(x) OVER (ORDER BY n ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) FROM (VALUES (1, 1.0e20::float8), (2, 1.0::float8)) AS v (n,x);
This query returns <literal>0</literal> as its second result, rather than the
expected answer of <literal>1</literal>. The cause is the limited precision of
floating-point values: adding <literal>1</literal> to <literal>1e20</literal> results
in <literal>1e20</literal> again, and so subtracting <literal>1e20</literal> from that
yields <literal>0</literal>, not <literal>1</literal>. Note that this is a limitation
of floating-point arithmetic in general, not a limitation
of <productname>PostgreSQL</productname>.
この問い合わせは 2行目の結果が期待した1
ではなく0
を返します。
原因は、浮動小数点値で制限された精度です:1e20
に1
を加えても結果は再び1e20
になります。その結果から1e20
を引くと1
ではなく0
になります。
これは、PostgreSQL限定ではなくて、一般的な浮動小数点演算の制限であることに注意してください。
Aggregate functions can use polymorphic state transition functions or final functions, so that the same functions can be used to implement multiple aggregates. See <xref linkend="extend-types-polymorphic"/> for an explanation of polymorphic functions. Going a step further, the aggregate function itself can be specified with polymorphic input type(s) and state type, allowing a single aggregate definition to serve for multiple input data types. Here is an example of a polymorphic aggregate: 集約関数は多様状態遷移関数や多様最終関数を使用することができます。これにより、同じ関数を使用して複数の集約を実装することができます。 36.2.5に多様関数の説明があります。 もう少し細かく言うと、集約関数自体が、単一の集約定義で複数の入力データ型を扱うことができるように、多様入力型(複数可)と多様状態型を指定することができるということです。 以下に多様型の集約の例を示します。
CREATE AGGREGATE array_accum (anycompatible) ( sfunc = array_append, stype = anycompatiblearray, initcond = '{}' );
Here, the actual state type for any given aggregate call is the array type
having the actual input type as elements. The behavior of the aggregate
is to concatenate all the inputs into an array of that type.
(Note: the built-in aggregate <function>array_agg</function> provides similar
functionality, with better performance than this definition would have.)
ここでは、任意の呼び出しが出来る集約として実際の状態型を(実際の入力型がその要素となる)配列型にしています。
この集約の動作は、その配列型に全ての入力を連結することです。
(組み込みの集約関数array_agg
は、この定義での動作よりもより良い性能で、類似の機能を提供しています。)
Here's the output using two different actual data types as arguments: 以下に2つの異なる実データ型を引数として使用した出力例を示します。
SELECT attrelid::regclass, array_accum(attname) FROM pg_attribute WHERE attnum > 0 AND attrelid = 'pg_tablespace'::regclass GROUP BY attrelid; attrelid | array_accum ---------------+--------------------------------------- pg_tablespace | {spcname,spcowner,spcacl,spcoptions} (1 row) SELECT attrelid::regclass, array_accum(atttypid::regtype) FROM pg_attribute WHERE attnum > 0 AND attrelid = 'pg_tablespace'::regclass GROUP BY attrelid; attrelid | array_accum ---------------+--------------------------- pg_tablespace | {name,oid,aclitem[],text[]} (1 row)
Ordinarily, an aggregate function with a polymorphic result type has a
polymorphic state type, as in the above example. This is necessary
because otherwise the final function cannot be declared sensibly: it
would need to have a polymorphic result type but no polymorphic argument
type, which <command>CREATE FUNCTION</command> will reject on the grounds that
the result type cannot be deduced from a call. But sometimes it is
inconvenient to use a polymorphic state type. The most common case is
where the aggregate support functions are to be written in C and the
state type should be declared as <type>internal</type> because there is
no SQL-level equivalent for it. To address this case, it is possible to
declare the final function as taking extra <quote>dummy</quote> arguments
that match the input arguments of the aggregate. Such dummy arguments
are always passed as null values since no specific value is available when the
final function is called. Their only use is to allow a polymorphic
final function's result type to be connected to the aggregate's input
type(s). For example, the definition of the built-in
aggregate <function>array_agg</function> is equivalent to
通常、上記の例のように多様型の結果を返す集約関数は多様状態型を持ちます。
それは、最終関数を適正に宣言するために以下が必要になります。結果の型は多様型であり、引数の型は多様型でない必要があります。そうでないとCREATE FUNCTION
は、呼び出しから結果の型を推定することができないので拒否されます。
しかし、状態型として多様型を使用するのは時に不便です。
最も一般的なケースでは集約サポート関数は、C言語で状態型をinternal(内部データ)
と宣言して書かれる必要があります。なぜなら、SQLには同等のものがないためです。
このケースに対処するために、集約の入力引数と一致する追加の「ダミー」引数を取るように最終関数を宣言することが可能です。
最終関数が呼び出されたときに特定の値を使用できないため、このようなダミー引数は常にnull値として渡されます。
それらは、多様最終関数の結果の型を集約の入力型(複数可)に合わせる場合のみ使用します。
例えば以下の定義は、組み込み集約のarray_agg
と等価です。
CREATE FUNCTION array_agg_transfn(internal, anynonarray) RETURNS internal ...; CREATE FUNCTION array_agg_finalfn(internal, anynonarray) RETURNS anyarray ...; CREATE AGGREGATE array_agg (anynonarray) ( sfunc = array_agg_transfn, stype = internal, finalfunc = array_agg_finalfn, finalfunc_extra );
Here, the <literal>finalfunc_extra</literal> option specifies that the final
function receives, in addition to the state value, extra dummy
argument(s) corresponding to the aggregate's input argument(s).
The extra <type>anynonarray</type> argument allows the declaration
of <function>array_agg_finalfn</function> to be valid.
ここで、finalfunc_extra
オプションは最終関数が状態値に加えて、集約の入力引数(複数可)に対応する追加のダミー引数(複数可)を受け取れることを指定します。
array_agg_finalfn
の追加引数anynonarray
により有効であると宣言をすることができます。
An aggregate function can be made to accept a varying number of arguments
by declaring its last argument as a <literal>VARIADIC</literal> array, in much
the same fashion as for regular functions; see
<xref linkend="xfunc-sql-variadic-functions"/>. The aggregate's transition
function(s) must have the same array type as their last argument. The
transition function(s) typically would also be marked <literal>VARIADIC</literal>,
but this is not strictly required.
集約関数は、通常の関数の場合とほとんど同じ方法で、最後の引数をVARIADIC
配列として宣言することで、可変長の引数を受け入れるようにすることができます。 36.5.6を参照してください。
集約の遷移関数(複数可)は、それら最後の引数と同じ配列型を持っている必要があります。
遷移関数(複数可)は、典型的には、VARIADIC
付きになりますが、これは必須ではありません。
Variadic aggregates are easily misused in connection with
the <literal>ORDER BY</literal> option (see <xref linkend="syntax-aggregates"/>),
since the parser cannot tell whether the wrong number of actual arguments
have been given in such a combination. Keep in mind that everything to
the right of <literal>ORDER BY</literal> is a sort key, not an argument to the
aggregate. For example, in
可変長集約は、ORDER BY
オプション(4.2.7を参照してください)との組み合わせでは、パーサが実引数かどうかを見分けることができないので、簡単に誤用されるようになります。
ORDER BY
の右側にあるすべてのものは、集約への引数ではなく、ソートキーであることに留意してください。
例えば、
SELECT myaggregate(a ORDER BY a, b, c) FROM ...
the parser will see this as a single aggregate function argument and three sort keys. However, the user might have intended パーサには集約関数の引数1つと3つのソートキーと見えます。 しかし、これは以下のようにユーザが意図している可能性があります。
SELECT myaggregate(a, b, c ORDER BY a) FROM ...
If <literal>myaggregate</literal> is variadic, both these calls could be
perfectly valid.
もしmyaggregate
が可変長引数の場合、これらの呼び出しが両方とも妥当かもしれません。
For the same reason, it's wise to think twice before creating aggregate functions with the same names and different numbers of regular arguments. 同じ理由で、通常の引数の数とは違う同じ名前の集約関数を作成する前に二度考えるのが賢明です。
The aggregates we have been describing so far are <quote>normal</quote>
aggregates. <productname>PostgreSQL</productname> also
supports <firstterm>ordered-set aggregates</firstterm>, which differ from
normal aggregates in two key ways. First, in addition to ordinary
aggregated arguments that are evaluated once per input row, an
ordered-set aggregate can have <quote>direct</quote> arguments that are
evaluated only once per aggregation operation. Second, the syntax
for the ordinary aggregated arguments specifies a sort ordering
for them explicitly. An ordered-set aggregate is usually
used to implement a computation that depends on a specific row
ordering, for instance rank or percentile, so that the sort ordering
is a required aspect of any call. For example, the built-in
definition of <function>percentile_disc</function> is equivalent to:
これまでに記述された集約は「通常の」集約です。
PostgreSQLは、順序集合集約もサポートします。それは、通常の集約とは2つの大きな違いがあります。
第一に、入力行ごとに評価される通常の集約引数に加えて、順序集合集約は、集約の呼び出しの時に一度だけ評価される「直接」引数を持つことが出来ます。
第二に、集約引数の構文は通常、明示的にソート順を指定します。
順序集合集約は通常、呼び出すソート順が必要な局面、例えば順位や百分位数(パーセンタイル)のような特定の行の順序に依存して計算する実装のために使用されます。
例えば、以下は組み込み関数percentile_disc
の定義と同じです。
CREATE FUNCTION ordered_set_transition(internal, anyelement) RETURNS internal ...; CREATE FUNCTION percentile_disc_final(internal, float8, anyelement) RETURNS anyelement ...; CREATE AGGREGATE percentile_disc (float8 ORDER BY anyelement) ( sfunc = ordered_set_transition, stype = internal, finalfunc = percentile_disc_final, finalfunc_extra );
This aggregate takes a <type>float8</type> direct argument (the percentile
fraction) and an aggregated input that can be of any sortable data type.
It could be used to obtain a median household income like this:
この集約は、float8
型の直接引数(百分位数)と、任意のソート可能なデータ型を集約の入力として取ります。
それは、以下のように家計所得の中央値を得ることができます。
SELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY income) FROM households; percentile_disc ----------------- 50489
Here, <literal>0.5</literal> is a direct argument; it would make no sense
for the percentile fraction to be a value varying across rows.
ここで0.5
は直接の引数です。百分位数が行毎に変化する値であったら意味がありません。
Unlike the case for normal aggregates, the sorting of input rows for
an ordered-set aggregate is <emphasis>not</emphasis> done behind the scenes,
but is the responsibility of the aggregate's support functions.
The typical implementation approach is to keep a reference to
a <quote>tuplesort</quote> object in the aggregate's state value, feed the
incoming rows into that object, and then complete the sorting and
read out the data in the final function. This design allows the
final function to perform special operations such as injecting
additional <quote>hypothetical</quote> rows into the data to be sorted.
While normal aggregates can often be implemented with support
functions written in <application>PL/pgSQL</application> or another
PL language, ordered-set aggregates generally have to be written in
C, since their state values aren't definable as any SQL data type.
(In the above example, notice that the state value is declared as
type <type>internal</type> — this is typical.)
Also, because the final function performs the sort, it is not possible
to continue adding input rows by executing the transition function again
later. This means the final function is not <literal>READ_ONLY</literal>;
it must be declared in <link linkend="sql-createaggregate"><command>CREATE AGGREGATE</command></link>
as <literal>READ_WRITE</literal>, or as <literal>SHAREABLE</literal> if
it's possible for additional final-function calls to make use of the
already-sorted state.
通常の集約の場合とは違って、順序集合集約のための入力行のソートは、裏側でおこなわれていません。それは集約のサポート関数の責任です。
典型的な実装方法は、集約の状態値に「tuplesort」オブジェクトへの参照を保持し、そのオブジェクトに入ってくる行を供給した後、ソートを完了し、最終関数内でデータを読み出すことです。
この設計は、最終関数がソートされるデータに追加の「架空」行を注入するなどの特別な操作を実行するのを可能にします。
通常の集約は多くの場合、PL/pgSQLまたは別のPL言語で書かれたサポート関数で実装することができますが、順序集合集約は状態値が任意のSQLデータ型のように定義可能ではないため一般的にC言語で書かれます。
(上の例では、状態値が内部
型 — として宣言されていることに気づくでしょう。これは典型的なものです。)
また、最終関数がソートを実行しますので、遷移関数を後で再び実行し、引き続き入力行を追加することはできません。
これは最終関数がREAD_ONLY
ではないことを意味します。追加の最終関数呼び出しで既にソートされた状態を使えるのなら、CREATE AGGREGATE
でREAD_WRITE
またはSHAREABLE
と宣言しなければなりません。
The state transition function for an ordered-set aggregate receives
the current state value plus the aggregated input values for
each row, and returns the updated state value. This is the
same definition as for normal aggregates, but note that the direct
arguments (if any) are not provided. The final function receives
the last state value, the values of the direct arguments if any,
and (if <literal>finalfunc_extra</literal> is specified) null values
corresponding to the aggregated input(s). As with normal
aggregates, <literal>finalfunc_extra</literal> is only really useful if the
aggregate is polymorphic; then the extra dummy argument(s) are needed
to connect the final function's result type to the aggregate's input
type(s).
順序集合集約のための状態遷移関数は、現在の状態値を加えた行ごとに集約入力値を受信し、更新された状態値を返します。
これは通常の集約と同じ定義ですが、(もしあっても)直接の引数が提供されていないことに注意してください。
最終関数は、最後の状態値、もしあれば直接の引数の値、および(finalfunc_extra
が指定された場合)集約入力(複数)に対応するnull値を受信します。
通常の集約と同様に、finalfunc_extra
は集約が多様(型)である場合にのみ便利です。そのとき集約の入力型(複数可)が、最終関数の結果の型と合わせるために追加のダミー引数が必要になります。
Currently, ordered-set aggregates cannot be used as window functions, and therefore there is no need for them to support moving-aggregate mode. 現在、順序集合集約は、ウィンドウ関数として使用することができないので移動集約モードをサポートする必要はありません。
Optionally, an aggregate function can support <firstterm>partial aggregation</firstterm>. The idea of partial aggregation is to run the aggregate's state transition function over different subsets of the input data independently, and then to combine the state values resulting from those subsets to produce the same state value that would have resulted from scanning all the input in a single operation. This mode can be used for parallel aggregation by having different worker processes scan different portions of a table. Each worker produces a partial state value, and at the end those state values are combined to produce a final state value. (In the future this mode might also be used for purposes such as combining aggregations over local and remote tables; but that is not implemented yet.) 省略可能ですが、集約関数は部分集約をサポート出来ます。 部分集約の考え方は、入力データの異なるサブセットに状態遷移関数を独立して実行し、その後、それらのサブセットから得られた状態値を結合します。こうすることで、単一の操作ですべての入力をスキャンした結果であったのと同じ状態値を生成します。 このモードは、別のワーカープロセスをテーブルの異なる部分をスキャンさせることによって並列集約のために使用することが出来ます。 それぞれのワーカーが、部分状態値を生成し、最後にこれらの状態値を結合して最終状態値を生成します。 (将来このモードは、ローカルとリモートのテーブルの集計を結合させるなどの目的のために使用されるかもしれません。それはまだ実装されていません。)
To support partial aggregation, the aggregate definition must provide a <firstterm>combine function</firstterm>, which takes two values of the aggregate's state type (representing the results of aggregating over two subsets of the input rows) and produces a new value of the state type, representing what the state would have been after aggregating over the combination of those sets of rows. It is unspecified what the relative order of the input rows from the two sets would have been. This means that it's usually impossible to define a useful combine function for aggregates that are sensitive to input row order. 部分集約をサポートするためには、集約定義が結合関数を提供しなければなりません。 それは、2つの集約の状態型(入力行の2つのサブセットに対する集約した結果を表わす)の値を取り、状態型の新しい値を生成します。状態は、それらの行の集合の組み合わせを集約した後であろうものを表します。 2つのセットからの入力行の相対的な順序であったであろうものが指定されません。 これは入力行の順序に敏感な集約のための結合関数を定義することは通常不可能だということを意味します。
As simple examples, <literal>MAX</literal> and <literal>MIN</literal> aggregates can be
made to support partial aggregation by specifying the combine function as
the same greater-of-two or lesser-of-two comparison function that is used
as their transition function. <literal>SUM</literal> aggregates just need an
addition function as combine function. (Again, this is the same as their
transition function, unless the state value is wider than the input data
type.)
簡単な例を示します。MAX
とMIN
集約は、その遷移関数として使用される「2つの大なり」比較、又は「2つの小なり」比較関数と同じ結合関数を指定することで部分集約をサポートすることが出来ます。
SUM
集約は結合関数として加算関数が必要になります。
(ここでも、入力データ型よりも状態値が広い場合を除き遷移関数と同じです。)
The combine function is treated much like a transition function that
happens to take a value of the state type, not of the underlying input
type, as its second argument. In particular, the rules for dealing
with null values and strict functions are similar. Also, if the aggregate
definition specifies a non-null <literal>initcond</literal>, keep in mind that
that will be used not only as the initial state for each partial
aggregation run, but also as the initial state for the combine function,
which will be called to combine each partial result into that state.
結合関数は、2番目の引数として、基本となる入力型ではなく状態型の値を取りますが、遷移関数のように扱われています。
具体的には、null値とstrict関数に対処するためのルールは似ています。
また、initcond
が非nullである集約定義を指定する場合、各部分集約の実行のための初期状態として使用されるだけでなく、各部分の結果をその状態に結合するために呼び出される結合関数の初期状態としても使用されることに留意してください。
If the aggregate's state type is declared as <type>internal</type>, it is
the combine function's responsibility that its result is allocated in
the correct memory context for aggregate state values. This means in
particular that when the first input is <literal>NULL</literal> it's invalid
to simply return the second input, as that value will be in the wrong
context and will not have sufficient lifespan.
集約の状態型がinternal
で宣言されている場合、その結果が集約状態値の正しいメモリコンテキストに割り当てられていることは結合関数の責任です。
これは特に、以下のことを意味します。最初の入力がNULL
だと、単純に2番目の入力を返すのは無効です。なぜなら、その値が間違ったコンテキストになり、そして十分な寿命を持っていないことになります。
When the aggregate's state type is declared as <type>internal</type>, it is
usually also appropriate for the aggregate definition to provide a
<firstterm>serialization function</firstterm> and a <firstterm>deserialization
function</firstterm>, which allow such a state value to be copied from one process
to another. Without these functions, parallel aggregation cannot be
performed, and future applications such as local/remote aggregation will
probably not work either.
集約の状態型をinternal
で宣言することは、シリアライズ関数とデシリアライズ関数を提供するために通常適切です。これらの関数は、状態値を1つのプロセスから別のプロセスにコピーすることを可能にします。
これらの関数がなければ、並列集約を行うことができず、ローカル/リモート集約などの将来のアプリケーションも、おそらく動作しません。
A serialization function must take a single argument of
type <type>internal</type> and return a result of type <type>bytea</type>, which
represents the state value packaged up into a flat blob of bytes.
Conversely, a deserialization function reverses that conversion. It must
take two arguments of types <type>bytea</type> and <type>internal</type>, and
return a result of type <type>internal</type>. (The second argument is unused
and is always zero, but it is required for type-safety reasons.) The
result of the deserialization function should simply be allocated in the
current memory context, as unlike the combine function's result, it is not
long-lived.
シリアライズ関数は、internal
の単一の引数を取り、フラットなblobのバイト状態値パッケージを表わすbytea
型を返します。
逆にデシリアライズ関数はその変換を逆にします。
bytea
型とinternal
型の2つの引数を取り、internal
型を返します。
(第2引数は使用せず常に0ですが、型の安全性の理由のために必要とされます。)
デシリアライズ関数の結果は単純に、現在のメモリコンテキストに割り当てる必要があります。結合関数の結果とは異なり、長寿命でありません。
Worth noting also is that for an aggregate to be executed in parallel,
the aggregate itself must be marked <literal>PARALLEL SAFE</literal>. The
parallel-safety markings on its support functions are not consulted.
集約を並列に実行するために、集約自体にPARALLEL SAFE
マークが、されなければならないというのは注目する価値があります。
それのサポート関数のパラレルセーフマークは参照されません。
A function written in C can detect that it is being called as an
aggregate support function by calling
<function>AggCheckCallContext</function>, for example:
C言語で作成された関数は、AggCheckCallContext
を呼び出して、集約サポート関数として呼び出されているかを検出することができます。
例えば、
if (AggCheckCallContext(fcinfo, NULL))
One reason for checking this is that when it is true, the first input
must be a temporary state value and can therefore safely be modified
in-place rather than allocating a new copy.
See <function>int8inc()</function> for an example.
(While aggregate transition functions are always allowed to modify
the transition value in-place, aggregate final functions are generally
discouraged from doing so; if they do so, the behavior must be declared
when creating the aggregate. See <xref linkend="sql-createaggregate"/>
for more detail.)
この検査を行う理由の1つは、これが真の場合、先頭の入力は一時的な状態値であるはずなので、新規に割り当ててコピーを持つことなくそのまま変更しても安全だからです。
例としてint8inc()
を参照してください。
(集約遷移関数は常に遷移値をその場で変更できますが、集約最終関数ではそのようなことをするのは一般には勧められません。もし、そうするなら集約を定義する時にその振舞いを宣言しなければなりません。
より詳しくはCREATE AGGREGATEを見てください。)
The second argument of <function>AggCheckCallContext</function> can be used to
retrieve the memory context in which aggregate state values are being kept.
This is useful for transition functions that wish to use <quote>expanded</quote>
objects (see <xref linkend="xtypes-toast"/>) as their state values.
On first call, the transition function should return an expanded object
whose memory context is a child of the aggregate state context, and then
keep returning the same expanded object on subsequent calls. See
<function>array_append()</function> for an example. (<function>array_append()</function>
is not the transition function of any built-in aggregate, but it is written
to behave efficiently when used as transition function of a custom
aggregate.)
AggCheckCallContext
の第2引数は、集約の状態値が保管されているメモリコンテキストを取得するために使用できます。
これは状態値として「展開された」オブジェクト(36.13.1を参照)を使用する遷移関数に便利です。
最初の呼び出しで、遷移関数はメモリコンテキストが集約状態のコンテキストの子である展開されたオブジェクトを返し、その後の呼び出しで同じ展開されたオブジェクトを保持し続ける必要があります。
array_append()
の例を参照してください。
(array_append()
は組み込み集約の遷移関数ではありませんが、カスタム集約の遷移関数で使用すると効率的に動作するように書かれています。)
Another support routine available to aggregate functions written in C
is <function>AggGetAggref</function>, which returns the <literal>Aggref</literal>
parse node that defines the aggregate call. This is mainly useful
for ordered-set aggregates, which can inspect the substructure of
the <literal>Aggref</literal> node to find out what sort ordering they are
supposed to implement. Examples can be found
in <filename>orderedsetaggs.c</filename> in the <productname>PostgreSQL</productname>
source code.
別のサポートルーチンとしてC言語で書かれたAggGetAggref
集約関数が利用可能です。それは、集約の呼び出しを定義するAggref
パースノードを返します。
これは主に順序集合集約で有用です。これはソートの順序をどう実現するかAggref
ノードの内部構造まで検査することができます。
その例は、PostgreSQLソースコード中のorderedsetaggs.c
から見つけることができます。