PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Não faça nada em um procedimento de gatilho


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: