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