Postgres 9.4でトリガー関数を記述しようとしています。このようなもの(まだ機能していません):
CREATE FUNCTION set_point_from_coords(source _regclass, target _regclass)
RETURNS trigger AS $func$
BEGIN
NEW.target := ST_SetSRID(ST_Point(NEW.source[1], NEW.source[2]), 4326);
RETURN NEW;
END;
$func$ LANGUAGE plpgsql
この場合、target
はgeometry
型の列で、source
は10進数の配列です。
行がcoords
配列で挿入されている場合、それをpoint
に変換します。上記は列名をハードコーディングした場合に機能しますが、同じ関数を使用して、異なるテーブルと異なる列のペアに対して実行したいと考えています。また、INSERT
自体を直接制御することはできません。
これが私の実験の一部です: http://sqlfiddle.com/#!15/dddcd/1
これを見つけた 関連するブログ投稿 解析に本当に苦労しています。
挿入/更新の前ではなく、実行後に実行することもできます。
あなたはすべての起こり得る合併症が一緒になる場所を選ばなければなりませんでした。
SQL(またはPL/pgSQL)ではidentifiersをパラメーター化することはできません。そのためには、EXECUTE
を使用した動的SQLが必要です。
ただし、トリガー関数の特別なplpgsql変数NEW
は、EXECUTE
で実行される動的コード内では表示されません。
また、_CREATE TRIGGER
_のトリガー関数に引数として列名を渡すことにより、さらに複雑になります。
また、ターゲット列を動的にするだけでは不十分で、行の別の動的列からソース値をフェッチする必要があります。
関係するすべての問題を回避する方法を知らない限り、より単純なアプローチを試してみます。トリガーごとに個別のトリガー関数を記述し、動的SQLなしでターゲット列に割り当てます。
つまり、それはcanoneのコード行で実行できます-そして、多くの説明行。質問の元の例では、次のテーブル定義を想定しています。
_CREATE TABLE tbl (
tbl_id serial PRIMARY KEY,
geom geometry,
coords double precision[]
);
_
これを機能させるには、追加のモジュール hstore
が(データベースごとに1回)インストールされている必要があります。または、同じ目的で、ドキュメントに記載されていない json_populate_record()
/jsonb_populate_record()
の機能を使用することもできます。
_CREATE OR REPLACE FUNCTION trg_demo()
RETURNS trigger AS
$func$
BEGIN
EXECUTE format('SELECT ($1 #= hstore(%L, ST_SetSRID(ST_Point($1.%2$I[1], $1.%2$I[2]), 4326)::text)).*'
, TG_ARGV[0], TG_ARGV[1]) -- target (geom), source (coords)
USING NEW
INTO NEW;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
_
引き金:
_CREATE TRIGGER demo
BEFORE INSERT OR UPDATE ON tbl
FOR EACH ROW EXECUTE PROCEDURE trg_demo('geom', 'coords');
_
ここで何が起こっているのか理解できない場合は、上記のアドバイスを検討してください。
geometry
boldの動的計算をフォーマットして、これを理解しやすくしました。以下の単純なケースと比較してください。
db <> fiddle here-PostGISがインストールされていないため、point
ではなくgeometry
を使用します。
古い sqlfiddle 。
これはさらに単純なバージョンで、単にtext
値を割り当てるだけです(ターゲット列geom
がtext
である必要があります)。 boldの簡略化された部分:
_ EXECUTE format('SELECT ($1 #= hstore(%L, $1.%I::text)).*'
, TG_ARGV[0], TG_ARGV[1]) -- target (geom), source (coords)
USING NEW
INTO NEW;
_
コア機能は hstore演算子_#=
_ to(ドキュメントごと)です。
record
のフィールドをhstore
の一致する値に置き換えます
Target and sourceはどちらも新しい行の列であり、問題が複雑になります。ソース値が定数である場合、単純に次のことができます。
_NEW := NEW #= hstore(TG_ARGV[0], 'POINT(123.0 456.0)');
_
関連:
ただし、列名を解決してソース値をフェッチするには、動的SQLが必要です。
format()
を使用して、クエリ文字列を安全に連結します。
_TG_ARGV[0]
_および_TG_ARGV[1]
_ _CREATE TRIGGER
_によって渡された引数の(0ベース!)テキスト配列への最初の2つの要素にアクセスします。
_%I
_は、format()
に渡された引数をidentifier(SQLインジェクションに対して安全)として連結します。
_$1
_は、EXECUTE
句でUSING
に渡された値を参照します。
hstore
はtext
を取るため、ジオメトリを計算した後、_::text
_へのキャストが必要です。
Plpgsqlは行をターゲットの列ごとに割り当てるため、割り当てのために行NEW
を分解する必要があります。