postgresql - 在不递归的情况下更新触发器中的行
问题描述
我有两张桌子:
CREATE TABLE first (
id text primary key,
updated_at timestamp,
data text
);
CREATE TABLE second (
id text REFERENCES first (id),
book_error text,
);
当这些表中的任何一个更新时,我需要updated_at
始终更新第一个表中的字段。我写了这个:
CREATE FUNCTION update_timestamp() RETURNS trigger AS $$
BEGIN
UPDATE first
SET updated_at = current_timestamp
WHERE id = NEW.id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DO $$
DECLARE
t text;
BEGIN
FOR t IN
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public'
LOOP
EXECUTE format('CREATE TRIGGER update_timestamp
BEFORE INSERT OR UPDATE ON %I
FOR EACH ROW EXECUTE PROCEDURE update_timestamp()',
t);
END LOOP;
END;
$$ LANGUAGE plpgsql;
但它不起作用,因为我的触发器中的更新语句导致在执行之前再次调用此触发器。
如何在不再次触发触发器的情况下更新内部触发器?
解决方案
pg_trigger_depth()
- PostgreSQL 触发器的当前嵌套级别(如果未从触发器内部直接或间接调用,则为 0)
您可以在触发器函数中使用它来检查它是否从触发器内部调用
DO $$
DECLARE
t text;
BEGIN
FOR t IN
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public'
LOOP
EXECUTE format('CREATE TRIGGER update_timestamp
BEFORE INSERT OR UPDATE ON %I
FOR EACH ROW
WHEN (pg_trigger_depth() = 0)
EXECUTE PROCEDURE update_timestamp()',
t);
END LOOP;
END;
$$ LANGUAGE plpgsql;
test=# Insert into first select 1,now(), 'test';
INSERT 0 1
test=# select * from first;
id | updated_at | data
----+----------------------------+------
1 | 2018-10-29 20:18:25.227281 | test
(1 row)
test=# Insert into second select 1, 'test_error';
INSERT 0 1
test=# select * from first;
id | updated_at | data
----+----------------------------+------
1 | 2018-10-29 20:19:07.456737 | test
推荐阅读
- azure-ad-b2c - 在为自助密码重置发送密码之前验证电子邮件 Azure AD B2C
- java - Android中发生OutofMemory Exception时如何解释消息?
- azure - 具有 request.headers 值的 Azure Functions 代理 backendUri
- sql-server - 如何修复 SSDT 在我的 CREATE VIEW 语句“不明确”中标记随机列的问题?
- c - C中的宏和预处理器
- javascript - 接受动态 url 时不加载基本布局
- android - 如何在 react-native 中解决此错误?
- php - 如何将数据库结果序列化为 FCM/推送通知数据?
- assembly - 如何使8086清屏然后将光标移动到换行符以打印出下一个功能
- docker - 使用 docker secret 登录到容器内的 docker 注册表