状況:
fn_SetFoo()
table にレコードを挿入する関数がありますTableFoo
。
に挿入するたびに実行されるトリガー関数もありますTableFoo
。TableFooID
新しく挿入された行から新しい主キーを取得し、それを 2 番目のテーブルTableFooBar
に (外部キー制約を使用して) 挿入します。
実行するトリガーを作成しましたAFTER INSERT ON TableFoo FOR EACH ROW EXECUTE PROCEDURE fn_SetFooBar();
fn_SetFoo()
直接呼び出すと、すべてが期待どおりに機能します。
ただし、fn_NormalizeFoo()
一部のデータを処理し、処理fn_SetFoo()
した各レコードを呼び出す別の関数があります。
呼び出すとfn_NormalizeFoo()
、最初のレコードのみが処理され、関数が停止します。
質問:
の内容が直接実行されfn_NormalizeFoo()
たときにプロセス全体が実行されたときに呼び出されたときに、最初のレコードの後にプロセスが停止するのはなぜですか?fn_NormalizeFoo()
いくつかのコード:
--------------------------------------------------------
-- Insert Into TableFoo --
--------------------------------------------------------
CREATE OR REPLACE FUNCTION "example"."fn_SetFoo" (
IN "Foo1" INTEGER,
IN "Foo2" INTEGER,
IN "Foo3" INTEGER
) RETURNS "void" AS
$$
BEGIN
INSERT INTO
"example"."TableFoo"(
"Foo1",
"Foo2",
"Foo3"
)
VALUES
(
$1,
$2,
$3
);
RETURN;
EXCEPTION WHEN "unique_violation" THEN
-- DO NOTHING
END;
$$
LANGUAGE plpgsql;
--------------------------------------------------------
-- Insert Into TableFooBar --
--------------------------------------------------------
CREATE OR REPLACE FUNCTION "example"."fn_SetFooBar" (
IN "FooPK" INTEGER,
IN "BarPK" INTEGER
) RETURNS "void" AS
$$
BEGIN
INSERT INTO
"example"."TableFooBar"(
"FooPK",
"BarPK"
)
VALUES
(
$1,
$2
);
RETURN;
EXCEPTION WHEN "unique_violation" THEN
-- DO NOTHING
END;
$$
LANGUAGE plpgsql;
--------------------------------------------------------
-- Trigger Function --
--------------------------------------------------------
CREATE OR REPLACE FUNCTION "example"."tr_SetFooBar"() RETURNS TRIGGER AS
$$
BEGIN
PERFORM
"example"."fn_SetFooBar"(
"TableFoo"."FooPK",
"TableBar"."BarPK"
)
FROM
"example"."TableFoo" JOIN
"example"."TableBar" ON [SOMETHING TRUE]
WHERE
NEW.SOMECOLUMN = SOMETHING AND
[MORE STUFF IS TRUE];
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
--------------------------------------------------------
-- Trigger --
--------------------------------------------------------
CREATE TRIGGER "SetFooBar" AFTER INSERT ON "example"."Foo" FOR EACH ROW EXECUTE PROCEDURE "example"."tr_SetFooBar"();
--------------------------------------------------------
-- Normalize Foo --
--------------------------------------------------------
CREATE OR REPLACE FUNCTION "example"."fn_NormaliseFoo" (
IN "Param1" VARCHAR,
IN "Param2" VARCHAR,
IN "Param3" VARCHAR
) RETURNS "void" AS
$$
SELECT
"example"."fn_SetFoo" (
"Foo1",
"Foo2",
"Foo3"
)
FROM
[TABLES]
WHERE
[STUFF IS TRUE]
$$
LANGUAGE SQL;
ご覧のとおり、これは最初に投稿したものよりも少し複雑です。一般的な考え方は、各レコードが追加されるたびに多対多の関係を作成することです。
繰り返しますが、実行"example"."fn_NormaliseFoo"
は最初の行の後で失敗します。ただし、コンテンツを手動で実行すると、期待どおりに機能します。