Seu exemplo está quebrado. Origem e destino são os mesmos em seu
INSERT
no acionador, que deve gerar uma violação exclusiva toda vez (exceto ao inserir NULL) - suprimido por ON CONFLICT (test_name2) DO NOTHING
, então nada acontece no gatilho. Você também esquece a restrição exclusiva em seu
INSERT
original . Veja abaixo. INSERT INTO test2(test_name2)
VALUES(NEW.test_name2)
...
CREATE TRIGGER trigger_test
AFTER INSERT
ON test2
Comece com uma configuração menos confusa:
CREATE TABLE test1 (col1 text UNIQUE);
CREATE TABLE test2 (col2 text UNIQUE);
E é mais eficiente mover
pg_trigger_depth()
ao próprio gatilho. Então isso funcionaria, copiando linhas inseridas em test1
para test2
(e não o contrário), apenas para o primeiro nível de profundidade do gatilho: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;
Eu mantive como
AFTER
acionar. Pode ser um BEFORE
acionar também, mas aí você precisa RETURN NEW;
. CREATE TRIGGER trigger_test
AFTER INSERT ON test1 -- !!
FOR EACH ROW
WHEN (pg_trigger_depth() < 1) -- !!
EXECUTE PROCEDURE trig_test();
Por que
(pg_trigger_depth() < 1)
? Observação que você intercepta violações exclusivas em
test2
desta forma (nada acontece), mas violações únicas em test1
ainda levantaria uma exceção a menos que você tenha ON CONFLICT ... DO NOTHING
lá também. Seu teste é uma ilusão:Tem que ser:
INSERT INTO test1 values ('test') ON CONFLICT (col1) DO NOTHING;
Alternativa:encadeie dois INSERT
com um CTE
Se você tem controle sobre
INSERT
comandos em test1
, você pode fazer isso em vez do gatilho: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;
Relacionado:
- Inserir dados em 3 tabelas por vez usando Postgres
- PostgreSQL multi INSERT. ..RETURNING com várias colunas