手続き型関数
基本的な問題
2 次元配列の場合のように、配列変数の次元を宣言することは、float8[][]
ドキュメントを提供するだけです。この関連する回答の詳細を検討してください:
mapping postgresql text[][] type and Java type
1 次元配列と 2 次元配列を混同しています。2 次元配列を宣言しても (効果はありません)、1 次元配列になるだけです。
配列を初期化するには、次を使用しますarray_fill()
。
img := array_fill(0, ARRAY[rows,cols])
この例では、2 次元配列が生成されます。1 次元配列を生成する誤ったステートメントとは対照的です。
img := ARRAY( SELECT 0 FROM generate_series(1, rows* cols) );
表示される配列添字img[i * cols + j]
はほとんど意味がありません。最大値は初期化した値の 2 倍になり、「範囲外」エラーが発生します。私はあなたが意味すると思いますimg[i][j]
作業バージョン
すべてをまとめると、次のように機能します。
CREATE OR REPLACE FUNCTION f_array_fill(rows integer, cols integer
, OUT img float8[][]) AS
$func$
DECLARE
i int;
j int;
BEGIN
img := array_fill(0, ARRAY[rows,cols]);
FOR i IN 1 .. rows LOOP
FOR j IN 1 .. cols LOOP
img[i][j] := (i * cols + j)::float8;
END LOOP;
END LOOP;
END
$func$ LANGUAGE plpgsql;
電話:
SELECT f_array_fill(2,3);
結果:
{{4,5,6},{7,8,9}}
関数を便利にするには、生成された配列を返します。OUT
そのためのパラメーターを使用します。
優れたセットベースのバージョン
plpgsql では、ループと個々の代入は比較的低速です。この関連する回答で @Craig が説明しているように、配列処理のパフォーマンスが特に悪い:
Why is PostgreSQL array access so much fast in C than in PL/pgSQL?
代わりに、セットベースの操作を使用します。数値が大きいほど高速です。
多次元配列の集計関数
多次元配列を生成するには、カスタム集計関数が必要です。array_agg()
または、配列コンストラクターが 1 次元配列のみを生成します。この関連する回答で解決したように、それは十分に単純です:
Initial array in function to aggregate multi-dimensional array
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
,STYPE = anyarray
,INITCOND = '{}'
);
代替機能
この美しさを利用して、上記と同じことを行う単純な SQL 関数を構築できます。
CREATE OR REPLACE FUNCTION f_array_fill_sql(_rows integer, _cols integer)
RETURNS float8[][] AS
$func$
SELECT array_agg_mult(ARRAY[arr1]) AS arr2
FROM (
SELECT array_agg((i * $2 + j)::float8) AS arr1
FROM generate_series(1, $1) i
CROSS JOIN generate_series(1, $2) j
GROUP BY i
ORDER BY i
) sub
$func$ LANGUAGE sql
電話:
SELECT f_array_fill_sql(3,4);
結果:
{{4,5,6},{7,8,9}}
比較
数値が小さい場合、パフォーマンスの違いは無視できます。しかし、最初のバリアント (現在は最適化されていますが) は、数値が大きくなると急速に劣化します。試す:
EXPLAIN ANALYZE SELECT f_array_fill(100,100)
EXPLAIN ANALYZE SELECT f_array_fill_sql(100,100) -- ~ 50x faster!