Ditt exempel är trasigt. Källa och mål är samma i din INSERT
i utlösaren, vilket är skyldigt att skapa en unik överträdelse varje gång (förutom när du infogar NULL) - undertryckt av ON CONFLICT (test_name2) DO NOTHING
, så ingenting händer någonsin i avtryckaren.
Du glömmer också bort den unika begränsningen i din ursprungliga INSERT
. Se nedan.
INSERT INTO test2(test_name2)
VALUES(NEW.test_name2)
...
CREATE TRIGGER trigger_test
AFTER INSERT
ON test2
Börja med en mindre förvirrande inställning:
CREATE TABLE test1 (col1 text UNIQUE);
CREATE TABLE test2 (col2 text UNIQUE);
Och det är mer effektivt att flytta pg_trigger_depth()
till själva avtryckaren. Så det här skulle fungera, kopiera rader infogade i test1
till test2
(och inte åt andra hållet), bara för den första nivå av triggerdjup:
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;
Jag behöll den som AFTER
utlösare. Kan vara en BEFORE
trigger också, men där behöver du RETURN NEW;
.
CREATE TRIGGER trigger_test
AFTER INSERT ON test1 -- !!
FOR EACH ROW
WHEN (pg_trigger_depth() < 1) -- !!
EXECUTE PROCEDURE trig_test();
Varför (pg_trigger_depth() < 1)
?
Obs att du fångar unika överträdelser i test2
på detta sätt (ingenting händer), men unika överträdelser i test1
skulle fortfarande skapa ett undantag om du inte har ON CONFLICT ... DO NOTHING
där också. Ditt test är önsketänkande:
Måste vara:
INSERT INTO test1 values ('test') ON CONFLICT (col1) DO NOTHING;
Alternativ:Kedja två INSERT
med en CTE
Om du har kontroll över INSERT
kommandon på test1
, kan du göra detta istället för utlösaren:
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;
Relaterat:
- Infoga data i 3 tabeller åt gången med Postgres
- PostgreSQL multi INSERT. ..ÅTERKOMMANDE med flera kolumner