PostgreSQL 9.3 触发函数以参数化名称插入表
Posted
技术标签:
【中文标题】PostgreSQL 9.3 触发函数以参数化名称插入表【英文标题】:PostgreSQL 9.3 trigger function to insert into table with parameterized name 【发布时间】:2014-06-08 10:50:43 【问题描述】:我正在尝试对 Postgres 中的日志条目进行动态分区。我有 53 个子表(1 个用于每周的日志条目),并且希望使用触发器将 INSERT 路由到子表。
我使用INSERT INTO log5 VALUES (NEW.*)
运行该函数,它可以工作。
我改为使用EXECUTE
语句运行该函数,但它失败了。在EXECUTE
语句中,它将NEW
识别为表名,而不是传递给触发器函数的变量。关于如何解决的任何想法?谢谢!
错误:
查询:插入 log5 值(新。*) 上下文:PL/pgSQL 函数 log_roll_test() 第 6 行在 EXECUTE 语句 错误:缺少表“新”SQL 状态的 FROM 子句条目:42P01
我的功能:
CREATE FUNCTION log_roll_test() RETURNS trigger AS $body$
DECLARE t text;
BEGIN
t := 'log' || extract(week FROM NEW.updt_ts); --child table name
--INSERT INTO log5 VALUES (NEW.*);
EXECUTE format('INSERT INTO %I VALUES (NEW.*);', t);
RETURN NULL;
END;
$body$ LANGUAGE plpgsql;
我的触发器:
CREATE TRIGGER log_roll_test
BEFORE INSERT ON log FOR EACH ROW
EXECUTE PROCEDURE log_roll_test();
【问题讨论】:
NEW
无法识别,因为EXECUTE
无法引用外部变量。尝试使用USING
子句。 postgresql.org/docs/9.3/static/…
谢谢!我已经尝试过了,但它不起作用。它将 NEW 记录传递给语句,而 EXECUTE 语句将其视为字符串。即'(value1, value2, value3,,,)'。 Postgres 不喜欢将逗号放在一起,也不喜欢在值周围加上引号。我需要做一个 regexp_replace 来修改字符串,出于性能原因,我真的很想避免这种情况。
我什么都试过了,顺便说一句。非常接近于放弃并使用 CASE WHEN 语句(53 行)编写触发器并编写 pgScript 来创建 53 个单独的触发器函数。
【参考方案1】:
CREATE FUNCTION log_roll_test()
RETURNS trigger AS
$func$
BEGIN
EXECUTE format('INSERT INTO %I SELECT ($1).*'
, to_char(NEW.updt_ts, '"log"WW')) -- child table name
USING NEW;
RETURN NULL;
END
$func$ LANGUAGE plpgsql;
您不能在查询字符串中引用NEW
。 NEW
在函数体中可见,但在 EXECUTE
环境中不可见。最好的解决方案是传递USING
子句中的值。
我还用等效的to_char(NEW.updt_ts, '"log"WW')
替换了表名。 to_char()
在这里更快更简单。
【讨论】:
谢谢欧文!!!简单而优雅的解决方案。我将在 format() 语句中使用 %I.%I 以便添加模式限定符。它工作得很好,将使触发器功能适用于多个日志表。 @DavidWillis:模式名称从何而来?对于静态值%s
就足够了。 %I
仅用于清理动态值。如果架构和表名是动态的,a cast to regclass
would be an alternative。 Another related answer here.
良好的链接。架构名称是静态的。我最终将 tg_table_name 转换为 regclass。目标是让一个简单的触发器函数适用于多个日志表,我想我就在那里。感谢您的帮助!以上是关于PostgreSQL 9.3 触发函数以参数化名称插入表的主要内容,如果未能解决你的问题,请参考以下文章