行INSERT上的更新序列

时间:2014-04-30 08:09:47

标签: postgresql

我有一个在id字段上设置主键的表,该字段使用序列生成数字作为其默认值。插入记录时,此工作正常,序列正确更新。但是,如果我插入带有id字段的记录(例如从备份导入),则不会更新序列。

CREATE TABLE public.my_table (
  my_id integer NOT NULL DEFAULT NEXTVAL('my_id_seq'),
  name text,
  CONSTRAINT my_primary PRIMARY KEY (myid)
);

CREATE SEQUENCE public.my_id_seq
   START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;

这会更新序列:

INSERT INTO my_table (name) VALUES ('Bart');

这不是:

INSERT INTO my_table (my_id, name) VALUES (12, 'Bart');

当序列命中12时出现问题,我尝试插入没有ID。

有一种好的/标准的方法可以自动执行此操作吗?我知道MySQL在AUTO_INCREMENT列中做到了(这是我遇到这个问题的方式,我来自MySQL)。我在网上找了一些方法:使用触发器,或者在插入后手动更新序列,但是其中许多资源都很老了。也许版本9.1有一些功能可以解决这个问题?

1 个答案:

答案 0 :(得分:0)

这是一个已知的限制:在调用nextval()函数期间,序列会递增,这是您字段的默认值。当您在INSERT向该字段提供数据时,默认值的表达式不会评估,这就是未触及序列值的原因。

解决方法是在INSERT之前/之后设置触发器,以使用setval()手动修复序列的值。但是这样你应该也需要在该字段的UPDATE上设置一个触发器来修复序列的值,当你只是将一些现有的id更新为更高的id时

另一种解决方法是,您编写一个存储函数,该函数可以为该字段生成一个可用值。将字段的默认值设置为该函数的返回值。有点像,如:

LOOP
    result = nextval('my_id_seq');
    EXIT WHEN NOT EXISTS (SELECT * FROM my_table WHERE my_id = result);
END LOOP;
RETURN result;

但要注意:序列的默认功能对于并发插入是安全的(序列的当前状态是全局的 - 与事务无关)。如果您为这些字段提供显式值,则不会出现这种情况。