Postgres 创建触发器函数以在允许插入之前将值从一列复制到另一列
Posted
技术标签:
【中文标题】Postgres 创建触发器函数以在允许插入之前将值从一列复制到另一列【英文标题】:Postgres create trigger function to copy value from one column to another before allowing insert 【发布时间】:2021-10-26 20:40:59 【问题描述】:我正在尝试在 Postgres 13 中创建一个触发器函数,在插入或更新操作完成之前,它将值从两列复制到另外两列。
在更新/插入操作之前,我的表 test.run_conf
如下所示:
hostname | run_config_current | run_config_current_hash | run_config_last | run_config_last_hash |
---|---|---|---|---|
switch01 | old_txt_str | 32314322 |
当发生更新/插入时,我希望将 run_config_current
中的值复制到 run_config_last
并将 run_config_current_hash
复制到 run_config_last_hash
。然后允许对列 run_config_current
进行更新/插入操作 - 之后触发器函数将重新计算 run_config_current_hash
的值。
为了测试,我运行以下查询将新数据插入到列run_config_current
:
INSERT INTO test.run_conf (hostname, run_config_current) VALUES ('switch01', 'new_txt_str' )
ON CONFLICT (hostname) DO UPDATE SET run_config_current = excluded.run_config_current
但是发生的情况是表 test.run_conf
更新如下 - 新值被插入到 run_config_current
和 run_config_last
两列中:
hostname | run_config_current | run_config_current_hash | run_config_last | run_config_last_hash |
---|---|---|---|---|
switch01 | new_txt_str | 47173234 | new_txt_str | 32314322 |
我现在没有正常工作的触发器和功能是:
CREATE OR REPLACE FUNCTION test.run_conf_hash_gen_func()
RETURNS TRIGGER
SET SCHEMA 'test'
LANGUAGE plpgsql
AS $$
BEGIN
NEW.run_config_last := NEW.run_config_current;
NEW.run_config_last_hash := NEW.run_config_current_hash;
NEW.run_config_current_hash := MD5(NEW.run_config_current);
RETURN NEW;
END;
$$
CREATE TRIGGER run_conf_hash_gen_trig
BEFORE INSERT OR UPDATE on test.run_conf
FOR EACH ROW
EXECUTE PROCEDURE test.run_conf_hash_gen_func();
请帮助我理解为什么我的代码似乎将run_config_current
的新值复制到run_config_last
。谢谢!
【问题讨论】:
因为在执行UPDATE
时需要OLD.run_config_current
。这意味着在触发函数中,您需要区分 INSERT
或 UPDATE
,因为 INSERT
没有 OLD
值。请参阅TG_OP
此处plpgsql trigger function。
原来在 Postgres 11+ OLD
for INSERT
设置为 NULL
所以你不必防范 OLD
的 pre-11 行为在 @987654351 中未分配@.
【参考方案1】:
我想通了。我的问题是我引用了 NEW
var 作为要分配的值的参考。由于变量NEW
和OLD
是在触发器执行时设置的,但在更改之前,我的旧代码使用我通过INSERT/UPDATE 语句发送的值作为分配给我的_last 列的值。
这是我更新后的触发函数,它按预期工作。我注释掉了旧的/坏的行,下面的新行是有效的:
CREATE OR REPLACE FUNCTION test.run_conf_hash_gen_func()
RETURNS TRIGGER
SET SCHEMA 'test'
LANGUAGE plpgsql
AS $$
BEGIN
-- NEW.run_config_last := NEW.run_config_current;
NEW.run_config_last := OLD.run_config_current;
-- NEW.run_config_last_hash := NEW.run_config_current_hash;
NEW.run_config_last_hash := OLD.run_config_current_hash;
NEW.run_config_current_hash := MD5(NEW.run_config_current);
RETURN NEW;
END;
$$
【讨论】:
当操作是INSERT
时,这将不起作用,因为插入中没有 OLD
行。
@AdrianKlaver 是的,这实际上是所需的行为。如果它是 INSERT,则它是相关设备的全新条目,因此无需进行“最后”比较。在我的代码下一次运行时,它将从设备重新获取配置,然后在已经存在条目的地方执行更新,导致其他 2 列填充。
当我说它不起作用时,我的意思是,INSERT
将完全失败。很确定这不是你想要的。
@AdrianKlaver 嗯。我的 OP 包括我的代码将与“ON CONFICT”子句一起使用的插入查询。运行它几次它按预期工作。我还使用唯一的主机名运行简单的测试 INSERT,它们也可以正常工作。
嗯,事实证明我需要跟上文档。在 Postgres 10-'此变量在语句级触发器和 INSERT 操作中未分配。并且在 11+ '此变量在语句级触发器和 INSERT 操作中为空。'。习惯让我为 11 岁之前的行为编码。可能仍然会,但你的代码很好。以上是关于Postgres 创建触发器函数以在允许插入之前将值从一列复制到另一列的主要内容,如果未能解决你的问题,请参考以下文章
AWS Glue - 在插入之前截断目标 postgres 表