Вашият пример е счупен. Източникът и целта са еднакви във вашия INSERT
в тригера, който е длъжен да предизвика уникално нарушение всеки път (освен при вмъкване на NULL) - потиска се от ON CONFLICT (test_name2) DO NOTHING
, така че никога нищо не се случва в тригера.
Също така забравяте за уникалното ограничение във вашия оригинален INSERT
. Вижте по-долу.
INSERT INTO test2(test_name2)
VALUES(NEW.test_name2)
...
CREATE TRIGGER trigger_test
AFTER INSERT
ON test2
Започнете с по-малко объркваща настройка:
CREATE TABLE test1 (col1 text UNIQUE);
CREATE TABLE test2 (col2 text UNIQUE);
И е по-ефективно да преместите pg_trigger_depth()
към самия спусък. Така че това ще работи, копиране на редове, вмъкнати в test1
към test2
(а не обратното), само за първия ниво на дълбочина на задействане:
CREATE OR REPLACE FUNCTION trig_test()
RETURNS trigger AS
$func$
BEGIN
INSERT INTO test2(col2) -- !!
VALUES (NEW.col1) -- !!
ON CONFLICT (col2) DO NOTHING; -- !!
RETURN NULL;
END
$func$ LANGUAGE plpgsql;
Запазих го като AFTER
спусък. Може да бъде BEFORE
задействане, но там ще имате нужда RETURN NEW;
.
CREATE TRIGGER trigger_test
AFTER INSERT ON test1 -- !!
FOR EACH ROW
WHEN (pg_trigger_depth() < 1) -- !!
EXECUTE PROCEDURE trig_test();
Защо (pg_trigger_depth() < 1)
?
Забележка че прихващате уникални нарушения в test2
по този начин (нищо не се случва), но уникални нарушения в test1
пак ще повдигне изключение, освен ако нямате ON CONFLICT ... DO NOTHING
там също. Вашият тест е пожелателно мислене:
Трябва да бъде:
INSERT INTO test1 values ('test') ON CONFLICT (col1) DO NOTHING;
Алтернатива:Верига две INSERT
с CTE
Ако имате контрол над INSERT
команди на test1
, можете да направите това вместо тригера:
WITH ins1 AS (
INSERT INTO test1(col1)
VALUES ('foo') -- your value goes here
ON CONFLICT (col1) DO NOTHING
RETURNING *
)
INSERT INTO test2(col2)
SELECT col1 FROM ins1
ON CONFLICT (col2) DO NOTHING;
Свързани:
- Вмъкнете данни в 3 таблици наведнъж с помощта на Postgres
- PostgreSQL multi INSERT. ..ВРЪЩАНЕ с множество колони