5

为了在第二个表中自动添加一列以通过唯一索引将其绑定到第一个表,我有如下规则:

CREATE OR REPLACE RULE auto_insert AS ON INSERT TO user DO ALSO
INSERT INTO lastlogin (id) VALUES (NEW.userid);

如果user.userid是一个整数,这很好用。但是,如果它是一个序列(例如,类型serialbigserial),则插入到表lastlogin中的是下一个序列 id。所以这个命令:

INSERT INTO user (username) VALUES ('john');

会将列 [1, 'john', ...] 插入user但将列 [2, ...] 插入lastlogin。以下 2 种解决方法确实有效,除了第二种方法消耗两倍的序列,因为序列仍然是自动递增的:

CREATE OR REPLACE RULE auto_insert AS ON INSERT TO user DO ALSO
INSERT INTO lastlogin (id) VALUES (lastval());

CREATE OR REPLACE RULE auto_insert AS ON INSERT TO user DO ALSO
INSERT INTO lastlogin (id) VALUES (NEW.userid-1);

不幸的是,如果我插入多行,解决方法不起作用:

INSERT INTO user (username) VALUES ('john'), ('mary');

第一个解决方法将使用相同的 id,而第二个解决方法就是搞砸了。

是否可以通过 postgresql 规则执行此操作,还是我应该自己第二次插入lastlogin或使用行触发器?实际上,我认为当我访问NEW.userid时,行触发器也会自动增加序列。

4

1 回答 1

7

完全忘记规则。他们很糟糕

触发器对你来说更好。在 99% 的情况下,当有人认为他需要规则时。试试这个:

create table users (
  userid serial primary key,
  username text
);

create table lastlogin (
  userid int primary key references users(userid),
  lastlogin_time timestamp with time zone
);

create or replace function lastlogin_create_id() returns trigger as $$
  begin
    insert into lastlogin (userid) values (NEW.userid);
    return NEW;
  end;
$$
language plpgsql volatile;

create trigger lastlogin_create_id
  after insert on users for each row execute procedure lastlogin_create_id();

然后:

insert into users (username) values ('foo'),('bar');

select * from users;
用户名 | 用户名
--------+----------
      1 | 富
      2 | 酒吧
(2 行)
select * from lastlogin;
用户名 | 上次登录时间
--------+----------------
      1 |
      2 |
(2 行)
于 2010-02-12T17:06:19.850 回答