アーウィンによって解決されたこのコードがあります:
plpgsql関数で動的INSERT ON CONFLICT DO UPDATEを実行します
次に、トリガーでトリガー関数_insert_data_func
_をパラメーター(_model_cd
_、processdate
)で呼び出します。
さまざまなモデルがあるため、動的SQLを使用して物事を簡略化しようとしています。
機能:
_CREATE OR REPLACE FUNCTION insert_data_func()
RETURNS TRIGGER AS
$func$
DECLARE
model_cd text;
processdate text;
BEGIN
model_cd := TG_ARGV[0];
processdate := TG_ARGV[1];
EXECUTE
$x$INSERT INTO tb_moldsummary AS t
SELECT $1.machine
, $1.model
, split_part(lot, '_', 1)
, right(lot, position('_' IN lot) * -1)
, COUNT(lot)
, $1.datetimestamp
FROM model$x$ || to_char(now(), 'YYYYMM') || '
WHERE lot = $1.lot
AND machine = $1.machine
GROUP BY machine, model, lot
ON CONFLICT ON CONSTRAINT tb_summary_unique
DO UPDATE
SET machine = $1.machine
, totalshots = t.totalshots + 1
, datetimestamp = $1.datetimestamp'
USING NEW;
RETURN NEW;
END
$func$
LANGUAGE plpgsql;
_
トリガー:
_DO$$
BEGIN
EXECUTE $x$CREATE TRIGGER insert_data_trigger
AFTER INSERT ON modelsample$x$ || to_char(now(), 'YYYYMM') ||
' FOR EACH ROW EXECUTE PROCEDURE
insert_data_func' ||
(''modelsample''' || ',' || to_char(now(), 'YYYYMM') || ')';
END
$$;
_
トリガーは、モデルとプロセスの日付パラメーターをトリガー関数insert_data_func()
に渡します。しかし、私はこの誤ったメッセージを受け取ります。
エラー:リレーション "model_cd201707"は存在しません
行9:FROM model_cd201707
insert_data_func()
関数で「$ x $」を適切に使用する方法は、モデル名が_model_cd
_ variableから値を取得しない理由だと思います。
エラーメッセージには_relation "model_cd201707" does not exist
_と表示されます。 _search_path
_ にその名前のテーブルがないと思いますか?あなたの質問にはテーブル名の混乱があります。 _modelsample...
_、_model_cd...
_、_model...
_ _tb_moldsummary
_。ここに何かがありません...
それはさておき、渡されたパラメータ値を変数_model_cd
_とprocessdate
に割り当てた後、それらは(まだ)まったく使用されていません。
渡された2つのパラメーターがテーブル名の作成に使用されると想定すると、次のように機能する可能性があります。
_CREATE OR REPLACE FUNCTION trg_insert_data_func()
RETURNS TRIGGER AS
$func$
BEGIN
EXECUTE format(
$x$INSERT INTO tb_moldsummary AS t
SELECT $1.machine
, $1.model
, split_part($1.lot, '_', 1)
, right($1.lot, position('_' IN lot) * -1)
, COUNT(*) -- never null in this query
, $1.datetimestamp
FROM %I
WHERE lot = $1.lot
AND machine = $1.machine
GROUP BY machine, model, lot
ON CONFLICT ON CONSTRAINT tb_summary_unique -- constraint has same name?
DO UPDATE
SET machine = $1.machine
, totalshots = t.totalshots + 1
, datetimestamp = $1.datetimestamp
$x$, TG_ARGV[0]
)
USING NEW;
RETURN NEW;
END
$func$
LANGUAGE plpgsql;
_
トリガー(単一の連結パラメーターをテーブル名として渡す):
_DO
$$
BEGIN
EXECUTE format(
'CREATE TRIGGER insert_data_trigger
AFTER INSERT ON %1$s
FOR EACH ROW EXECUTE PROCEDURE trg_insert_data_func(%1$L)'
, 'modelsample' || to_char(now(), 'YYYYMM')
);
END
$$;
_
SQLステートメントの(引用符で囲まれていない)テーブル名に_%1$s
_を使用し、パラメータ(文字列リテラルとして引用符で囲まれている)に_%1$L
_を使用していることに注意してください。この場合、既知の正当な識別子には_%I
_は必要ありません。詳細は format()
のマニュアルを参照してください。
関数とテーブルの名前をスキーマで修飾して、曖昧さをなくしたい場合があります。 _public.modelsample
_のように。もっと:
トリガー定義に組み込まれた日付コンポーネントは、作成後は不変であることに注意してください。作成ステートメント自体(およびトリガー関数)のみが「動的」です。
関連:
But 不必要な複雑化のようです。トリガーが呼び出されるテーブルの名前を渡す必要はありません。 一部の特殊変数は、plpgsqlトリガー関数で自動的に使用できます 。特に:_TG_TABLE_SCHEMA
_および_TG_TABLE_NAME
_。したがって、トリガー関数で動的SQLを使用しますが、トリガー自体は単純で静的にすることができます。
_CREATE OR REPLACE FUNCTION trg_insert_data_func()
RETURNS TRIGGER AS
$func$
BEGIN
EXECUTE format(
$x$INSERT INTO tb_moldsummary AS t
SELECT $1.machine
, $1.model
, split_part($1.lot, '_', 1)
, right($1.lot, position('_' IN lot) * -1)
, COUNT(*) -- never null in this query
, $1.datetimestamp
FROM %I.%I -- !!
WHERE lot = $1.lot
AND machine = $1.machine
GROUP BY machine, model, lot
ON CONFLICT ON CONSTRAINT tb_summary_unique -- constraint has same name?
DO UPDATE
SET machine = $1.machine
, totalshots = t.totalshots + 1
, datetimestamp = $1.datetimestamp
$x$, TG_TABLE_SCHEMA, TG_TABLE_NAME -- !!
)
USING NEW;
RETURN NEW;
END
$func$
LANGUAGE plpgsql;
_
トリガー自体にはパラメーターがありません。