具有序列字段、规则和错误当前值/序列的 PostgreSQL

PostgreSQL with serial fields , rule and wrong currval / sequence

通常使用 PotsgreSQL 基于 CRUD 事件将记录插入日志 table 需要(至少)一个触发器和一个触发器函数。我试图使用 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');

主 table 和日志 table 有一个序列字段,我希望 - 在将一条记录插入 mydata 之后 - 在 mydata 中有一条记录 id1=1,以及mylog中的一条记录,其中logid=1(作为mydata记录的id),以及id2=1...在mydataid1=1 ,对...是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 这样做有什么理由吗?!

查看执行计划:

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 调用。

数据修改查询的规则很难搞定,你就踏入了一个典型的陷阱。使用触发器。