Pgクエリは配列を返します。私は小数点以下3桁にフォーマットされた各要素でそれを取得したいと思います。どのようにして配列の各要素に関数を適用できますか? (当然、間違った)次のようなもの -Postgresの配列列の各要素に関数を適用するには?
SELECT Round(ARRAY[1.53224,0.23411234], 2);
{1.532, 0.234}
私はPerlのmap
機能のようなものを探していますね。
Pgクエリは配列を返します。私は小数点以下3桁にフォーマットされた各要素でそれを取得したいと思います。どのようにして配列の各要素に関数を適用できますか? (当然、間違った)次のようなもの -Postgresの配列列の各要素に関数を適用するには?
SELECT Round(ARRAY[1.53224,0.23411234], 2);
{1.532, 0.234}
私はPerlのmap
機能のようなものを探していますね。
ストアドファンクションを作成する必要があります。ここでは何が必要ないものは次のとおりです。
CREATE OR REPLACE FUNCTION array_round(float[], int)
RETURNS float[]
AS
$$
DECLARE
arrFloats ALIAS FOR $1;
roundParam ALIAS FOR $2;
retVal float[];
BEGIN
FOR I IN array_lower(arrFloats, 1)..array_upper(arrFloats, 1) LOOP
retVal[I] := round(CAST(arrFloats[I] as numeric), roundParam);
END LOOP;
RETURN retVal;
END;
$$
LANGUAGE plpgsql
STABLE
RETURNS NULL ON NULL INPUT;
次に、このような何かを呼び出す:
# SELECT array_round(ARRAY[1.53224,0.23411234], 2);
array_round
-------------
{1.53,0.23}
(1 row)
あなたは、行セットに配列を有効にする必要があります。例えば、generate_series
を使用して:
SELECT ARRAY(SELECT ROUND(ARRAY[1.53224,0.23411234])[i], 2) FROM generate_series(1,2) AS s(i));
私はそれはかなり醜いと知っています。このようなマッピングを容易にするヘルパー関数が必要です。
おそらく(はい、それは、恐ろしい遅く、そして脆い動的なコードです)のようなもの:
CREATE OR REPLACE FUNCTION map_with_arg(TEXT, ANYARRAY, TEXT)
RETURNS ANYARRAY
IMMUTABLE STRICT
LANGUAGE 'plpgsql' AS
$$
DECLARE
i INTEGER;
t TEXT;
cmd TEXT;
BEGIN
FOR i IN array_lower($2, 1) .. array_upper($2, 1) LOOP
cmd := 'SELECT ('||quote_ident($1)||'('||quote_nullable($2[i])||', '||quote_nullable($3)||'))::TEXT';
EXECUTE cmd INTO t;
$2[i] := t;
END LOOP;
RETURN $2;
END;
$$;
select map_with_arg('repeat', array['can','to']::TEXT[], '2');
map_with_arg
---------------
{cancan,toto}
更新我々が全体のループのために単一の動的ステートメントを使用することができることを私に起こります。これにより、パフォーマンス上の懸念が軽減されます。
CREATE OR REPLACE FUNCTION map_with_arg(TEXT, ANYARRAY, TEXT)
RETURNS ANYARRAY
IMMUTABLE STRICT
LANGUAGE 'plpgsql' AS
$$
DECLARE
cmd TEXT;
rv TEXT;
BEGIN
cmd := 'SELECT ARRAY(SELECT (' || quote_ident($1)||'($1[i], '||quote_nullable($3)||'))::TEXT FROM generate_subscripts($1, 1) AS gs(i))';
EXECUTE cmd USING $2 INTO rv;
RETURN rv;
END;
$$;
ループ内の動的SQLは本当にひどい考えです。 plpgsqlでは実行しないでください。これは相対的な静的言語であり、perl、pythonまたは他のスクリプト言語のパターンはここでは適用できません。 –
はい、それはコードの前に私の文が言うことです。私はplpgsqlに呼び出される関数を渡したいので、この気の利いたこの例でそれを使いました。それはプログラミングの基本的な抽象であり、どの言語でもできることは有益なことです。もちろん、文字列としてそれを行い、新しい文を動的に作成する必要があるのは苦痛ですが、一般的なマッピング関数を記述したい場合は、これを考慮する必要があります。代わりに、100の非一般的なマッピング関数を記述する必要があります。 – Edmund
この抽象化形式が必要な場合は、独自のCモジュールを使用します。 PL/pgSQLは抽象コーディングのための言語ではありません。データベース側の有効でないコードは、パフォーマンスを大幅に低下させる可能性があります。 map_with_argsはC言語で実装された相対的なものでなければなりません –
まず、unnestを使用してセットにアレイを回す:
> SELECT n FROM unnest(ARRAY[1.53224,0.23411234]) AS n;
n
------------
1.53224
0.23411234
(2 rows)
次に、カラムに式を適用する:最後
> SELECT ROUND(n, 2) FROM unnest(ARRAY[1.53224,0.23411234]) AS n;
round
-------
1.53
0.23
(2 rows)
、バック設定を有効にするarray_aggを使用アレイに:
> SELECT array_agg(ROUND(n, 2)) FROM unnest(ARRAY[1.53224,0.23411234]) AS n;
array_agg
-------------
{1.53,0.23}
(1 row)
そして、それをユーザ定義の 'round(int []、int)'関数にラップすることもできます。 –
これは最も簡潔な解決策です。私はあなたがそれを構築する明確な方法が好きです。 – Edmund
postgres=# select array(select round(unnest(array[1.2,2.4,3,4])));
array
-----------
{1,2,3,4}
(1 row)
ベスト回答は – sudo
'array_agg()'(Joeyの解説を参照)と 'array()'(この解決策)にはいくつかのパフォーマンスの違いがありますか? –
@PeterKrauss私は今ベンチマークを行い、速度は同じです –
素晴らしい提案です。私は、この種の 'map'関数を常に適用する必要があるので、格納されたprocに行くと思います。格納されたprocに関数を渡すことができれば、それを真の 'map'関数に変換するfactory格納されたprocにすることができればさらに大きくなるでしょう。しかし、これは今のところうまくいくでしょう。もう一度、ありがとう。 – punkish
Re:関数を渡す:http://stackoverflow.com/questions/8346065/function-as-parameter-to-another-function-in-postgresに興味があります。 (これは理想とはほど遠いですが、そこからいくつか使用するかもしれません) – ruakh