我有一个在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有一些功能可以解决这个问题?
答案 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;
但要注意:序列的默认功能对于并发插入是安全的(序列的当前状态是全局的 - 与事务无关)。如果您为这些字段提供显式值,则不会出现这种情况。