我已经定义了一个BEFORE触发器,它可以执行以下操作:
虽然我知道在AFTER触发器而不是BEFORE触发器中执行conditionally write some changes to a different table
是惯用的,但是提取1和2的逻辑几乎是不可能的。
所以考虑到这一点,我遇到了一些问题:
我正在执行insert on conflict
,这会导致行更新触发两次BEFORE触发器:一次用于插入,一次用于更新。 (即:PG正确引发'id已存在的异常',但这发生在执行before-trigger之后)
这导致BEFORE触发器中的一些逻辑,例如写入更改,两次显然是错误的。
如何抵消这种情况?
虽然不是很优雅,但我可以想象当现有行以状态TG_OP = 'INSERT'
进入触发器时,在BEFORE触发器中手动抛出'id already exists'异常。这会使第一个触发器短路,让PG负责其余的事情:引发冲突,导致更新发生。
然而,我无法让它发挥作用。是否有可能手动引发异常,这是由'插入...在冲突'中提取的?
任何替代方案?
答案 0 :(得分:1)
也许您可以在第二个表上引入一个唯一约束,该约束检测何时输入两次相同的数据。然后你可以在第二个表上使用INSERT ... ON CONFLICT ... DO NOTHING
。
答案 1 :(得分:0)
你可以使用可写的CTE,我认为这只是PostgreSQL的扩展。它可以模拟UPSERT。
示例:
CREATE TABLE trigger_table (id int, column1 text, column2 int);
INSERT INTO trigger_table VALUES (13, 'test2', 5);
CREATE OR REPLACE FUNCTION trigger_fkey()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
BEGIN
raise exception 'test';
END;
$function$;
CREATE TRIGGER asdf BEFORE INSERT
ON trigger_table FOR EACH ROW
EXECUTE PROCEDURE trigger_fkey();
--works, update is done, insert not
WITH cte AS (UPDATE trigger_table SET column1 = 'test1', column2 = 1
WHERE id = 13 RETURNING id)
INSERT INTO trigger_table (id, column1, column2)
SELECT id, column1, column2
FROM (VALUES (13, 'test1', 1)) AS b(id, column1, column2)
WHERE id NOT IN(SELECT id FROM cte);
--after this before insert trigger will fire (on above insert) and exception is thrown
DELETE FROM trigger_table WHERE id = 13;