Twój przykład jest zepsuty. Źródło i cel są takie same w INSERT
w czynniku wyzwalającym, który z pewnością zgłosi unikalne naruszenie za każdym razem (z wyjątkiem wstawiania NULL) - pomijane przez ON CONFLICT (test_name2) DO NOTHING
, więc nic się nie dzieje w wyzwalaczu.
Zapominasz także o unikalnym ograniczeniu w oryginalnym INSERT
. Zobacz poniżej.
INSERT INTO test2(test_name2)
VALUES(NEW.test_name2)
...
CREATE TRIGGER trigger_test
AFTER INSERT
ON test2
Zacznij od mniej skomplikowanej konfiguracji:
CREATE TABLE test1 (col1 text UNIQUE);
CREATE TABLE test2 (col2 text UNIQUE);
I bardziej wydajne jest przeniesienie pg_trigger_depth()
do samego spustu. Więc to zadziała, kopiując wiersze wstawione do test1
do test2
(a nie odwrotnie), tylko w pierwszym poziom głębokości wyzwalania:
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;
Zachowałem to jako AFTER
cyngiel. Może być BEFORE
również wyzwalacz, ale tam potrzebujesz RETURN NEW;
.
CREATE TRIGGER trigger_test
AFTER INSERT ON test1 -- !!
FOR EACH ROW
WHEN (pg_trigger_depth() < 1) -- !!
EXECUTE PROCEDURE trig_test();
Dlaczego (pg_trigger_depth() < 1)
?
Uwaga że wyłapujesz unikalne naruszenia w test2
w ten sposób (nic się nie dzieje), ale unikalne naruszenia w test1
nadal zgłosi wyjątek, chyba że masz ON CONFLICT ... DO NOTHING
tam też. Twoim testem jest myślenie życzeniowe:
Musi być:
INSERT INTO test1 values ('test') ON CONFLICT (col1) DO NOTHING;
Alternatywnie:Połącz dwa INSERT
z CTE
Jeśli masz kontrolę nad INSERT
komendy na test1
, możesz to zrobić zamiast wyzwalacza:
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;
Powiązane:
- Wstawiaj dane w 3 tabelach jednocześnie za pomocą Postgresa
- PostgreSQL multi INSERT. ..POWRÓT z wieloma kolumnami