Postgresql 触发器在 NEW 和 OLD 记录上运行
Posted
技术标签:
【中文标题】Postgresql 触发器在 NEW 和 OLD 记录上运行【英文标题】:Postgresql trigger operating on both NEW and OLD records 【发布时间】:2018-03-29 19:51:56 【问题描述】:这主要是一个风格问题。
我有一个 AFTER INSERT OR UPDATE 触发器。我想针对任何可用的 NEW/OLD 记录运行 same 查询。与其让条件检查 TG_OP 并复制查询,确定哪些可用并循环它们的最简洁方法是什么?
示例代码:
CREATE FUNCTION myfunc() RETURNS TRIGGER AS $$
DECLARE
id int;
ids int[];
BEGIN
IF TG_OP IN ('INSERT', 'UPDATE') THEN
ids := ids || NEW.id;
END IF;
IF TG_OP IN ('UPDATE', 'DELETE') THEN
ids := ids || OLD.id;
END IF;
FOREACH id IN ARRAY ARRAY(SELECT DISTINCT UNNEST(ids))
LOOP
RAISE NOTICE 'myfunc called for % on id %', TG_OP, id;
/* RUN QUERY REFERENCING id */
END LOOP;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
是否有更短/更简单/更惯用的方法来实现这一目标?
【问题讨论】:
您在寻找ids := ids || new.id
吗? (但你必须将ids
初始化为一个空数组,而不是null
)详见手册:postgresql.org/docs/current/static/functions-array.html
我打算把它当作伪代码,因为我不知道使用数组是否是最好的方法。不过谢谢。我编辑了代码,所以它现在真的可以工作了。但是有没有更简单的方法?实现这一目标似乎非常复杂。
【参考方案1】:
数组处理和单独的SELECT DISTINCT
对于这项工作来说似乎太昂贵了。这应该更便宜:
CREATE FUNCTION myfunc()
RETURNS TRIGGER AS
$func$
DECLARE
_id int;
BEGIN
CASE TG_OP
WHEN 'INSERT', 'UPDATE' THEN
_id := NEW.id;
WHEN 'DELETE' THEN
_id := OLD.id;
END CASE;
FOR i IN 1..2 -- max 2 iterations
LOOP
RAISE NOTICE 'myfunc called for % on id %', TG_OP, _id;
/* RUN QUERY REFERENCING _id */
EXIT WHEN TG_OP <> 'UPDATE' OR i = 2; -- only continue in 1st round for UPDATE
EXIT WHEN _id = OLD.id; -- only continue for different value
_id := OLD.id;
END LOOP;
RETURN NULL;
END
$func$ LANGUAGE plpgsql;
相关:
BREAK statement in PL/pgSQL但我可能只是为每个 DML 语句编写一个单独的触发器函数和触发器。而是三个非常简单和快速的函数,而不是一个通用但复杂且速度较慢的函数。
【讨论】:
谢谢。是的,这有点复杂。好吧,作为一个必然的问题,你将如何命名/管理不同的对象?您是否有一个执行实际查询的 myfunc(int),然后是 myfunc_new_trig 和 myfunc_old_trig?那里有最佳实践的指针吗? 不是myfunc_new_trig
& myfunc_old_trig
,因为我将为INSERT
、UPDATE
和DELETE
设置三个单独的触发器(以及各自的触发器函数)——UPDATE
触发器是只有一个处理OLD
和 NEW
。 (根据myfunc(int)
中的实际查询,所有这些毕竟可能会被简化。但这仍未公开。)以上是关于Postgresql 触发器在 NEW 和 OLD 记录上运行的主要内容,如果未能解决你的问题,请参考以下文章
使用 :new 和 :old 在更新和插入之前触发 Oracle