首页 > 解决方案 > 具有串行字段、规则和错误的 currval / 序列的 PostgreSQL

问题描述

通常使用 PotsgreSQL 根据 CRUD 事件将记录插入日志表需要(至少)一个触发器和一个触发器函数。我尝试使用 Postgres RULES 使其更容易。它几乎可以工作,除了以下场景:

create table mydata ( somedata char(4) , id1 bigserial );
create table mylog ( logid bigint , op char(1), id2 bigserial );
create rule mydata_ilog as on insert to mydata do insert into mylog( logid , op ) values ( new.id1 ,'i' );
insert into mydata( somedata ) values ('0001');

主表和日志表有一个序列字段,我希望 - 在插入一条记录之后mydata- 在 mydata 中有一条记录,id1=1在 , 中有一条记录mylog,其中logid=1(作为 mydata 记录的 id),并且id2=1...在mydata, id1=1, 对 ... ay mylog,id2是 1, 对 ... 但是在mylog,logid字段是2, 并且为递增id1序列字段而创建的数据库序列是2...

select currval('mydata_id1_seq'); -- return 2 ?!
select last_value from mydata_id1_seq; -- return 2 ?!
select id1 from mydata -- return 1 ok 
select id2 from mydata -- return 1 ok 
select logid from mylog -- return 2 ?!

我已经用触发器和触发器功能解决了这个问题,工作正常。但是,PostgreSQL 有什么理由这样做吗?!

标签: postgresqltriggersrules

解决方案


看执行计划:

EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO mydata (somedata) VALUES ('0001');
                                                 QUERY PLAN                                                 
------------------------------------------------------------------------------------------------------------
 Insert on myschema.mydata
   ->  Result
         Output: '0001'::character(4), nextval('mydata_id1_seq'::regclass)
 
 Insert on myschema.mylog
   ->  Result
         Output: nextval('mydata_id1_seq'::regclass), 'i'::character(1), nextval('mylog_id2_seq'::regclass)
(7 rows)

规则使用用于mydata.id第二个语句的相同表达式重写查询,因此您nextval在两个语句中都有调用。

数据修改查询的规则很难做到正确,你只是踏入了一个典型的陷阱。使用触发器。


推荐阅读