Postgres における集約は 状態値と状態遷移関数 の集合で表現されています。つまり、ひとつの集約はインスタンスの処理に より変更された状態として定義することができます。新しい集約関数を 定義するためには、状態値、状態の初期値、そして状態遷移関数 のためのデータ型を選択します。状態遷移関数はただの普通の関数で、 集約以外の文脈でも使うことができます。求められる集約の結果が 動いている状態値のなかにあるべきデータと 違う場合は、最終関数も指定することができます。
したがって、集約のユーザに見える結果データ型の入力と結果に加え、 入力と結果の型のどちらとも違う内部状態値のデータ型があります。
もし最終関数を使わない集約を定義したとすると、それぞれの行の カラム値の動いている関数を計算する集約が出来ます。"Sum" は そのような集約の一例です。"Sum" はゼロから始まり常に現在の 行の値をその時点までの総和に追加します。例えば、もし Sum 集約 を複合数のデータ型で動くようにしたければ、そのデータ型の 加算関数だけが必要になります。集約定義は以下のようになります。
CREATE AGGREGATE complex_sum ( sfunc = complex_add, basetype = complex, stype = complex, initcond = '(0,0)' ); SELECT complex_sum(a) FROM test_complex; +------------+ |complex_sum | +------------+ |(34,53.9) | +------------+(実際の使用では、その集約は "sum" とだけ名付け Postgres が複合カラムにどの 合計をあてはめるかを見積もります。)
上記の "Sum" の定義は、もし非 NULL の入力値がなければゼロ (初期状態)を返します。その場合本来は代わりに NULL を返したい のではないかと思いますし、SQL92 では "Sum" がそのように動作する ことを期待しています。そうするためには単に "initcond" 句を省略 すれば、初期状態が NULL になります。通常はそうすると、sfunc が NULL 状態の入力をチェックしなければいけないということを意味しますが、 "Sum" 、そして "Max" や "Min" のような他の簡単な集約にとっては、 最初の非 NULL 入力値を状態変数に挿入し、二番目の非 NULL 入力値 でトランザクション関数をあてはめ始めれば十分です。 Postgresは、もし初期状態が NULL で トランザクション関数が "strict" とマークされている場合、 自動的にそれを実行します(つまり NULL 入力として呼び出されないためにです)。
もうひとつの "strict" トランザクション関数のデフォルト動作 としては、NULL 入力値が現われると前の状態値が変わらずに維持 されるということがあります。したがって NULL は無視されます。 もし NULL 入力の他の動作が必要な場合は、単にトランザクション関数 を非厳密として定義し、NULL 入力のテストとしてコーディングし 必要なことをすれば良いのです。
"Average" はもっと複雑な集約の一例です。それには二つの動いている 状態が必要になります。入力の合計と入力数のカウントです。最終的な 結果はこれらの値を分割することによって得られます。Average は 典型的に二要素の配列を状態遷移値として使って実装されます。 例えば、avg(float8)の組み込み 実装は以下のようになっています。
CREATE AGGREGATE avg ( sfunc = float8_accum, basetype = float8, stype = float8[], finalfunc = float8_avg, initcond = '{0,0}' );
更に詳しい情報はPostgreSQL ユーザガイド のCREATE AGGREGATEを見て下さい。