我有两个表:
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;
但是它不起作用,因为触发器中的update语句导致在执行之前再次调用此触发器。
如何在触发器内更新而不触发触发器?
答案 0 :(得分:1)
TG_TABLE_NAME
数据类型名称;引起触发器调用的表的名称。
在触发函数中使用变量:
CREATE OR REPLACE FUNCTION update_timestamp() RETURNS trigger AS $$
BEGIN
IF TG_TABLE_NAME = 'first' THEN
NEW.updated_at = current_timestamp;
ELSE
UPDATE first
SET updated_at = current_timestamp
WHERE id = NEW.id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
答案 1 :(得分:1)
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