如何解决 Potgresql 自动增量违反唯一约束的问题? Postgres 中是否有一些选项可以在正确插入后设置序列值? 当 Posgres 尝试使用已插入的 id 创建新行时,我总是收到错误。 我从来没有在 Mysql 上经历过类似的事情。当我从数据库中删除一行时,Postgresql 在下一次插入时使用已删除的 id 并为此设置下一个自动增量值。接下来插入尝试插入已经在表中的 id 并引发主键唯一约束冲突。 这是您可以在其中查看主键定义的表属性之一。
这是两个表的一些DDL
CREATE TABLE IF NOT EXISTS public.tiers
(
id bigint NOT NULL DEFAULT nextval('tiers_id_seq'::regclass),
purchases integer,
audience character varying(50) COLLATE pg_catalog."default",
created_at timestamp(0) without time zone,
updated_at timestamp(0) without time zone,
disabled boolean,
CONSTRAINT tiers_pkey PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS public.company_categories
(
id bigint NOT NULL DEFAULT nextval('company_categories_id_seq'::regclass),
parent_id bigint,
sort integer DEFAULT 100,
CONSTRAINT company_categories_pkey PRIMARY KEY (id)
);
我猜想,您已经将一些带有 ID 的行导入/插入到数据库中,而没有改变顺序。在postgresql中,没有“自动增量”列类型。只有整数类型和序列(其他实体)的列,可以为您提供增量序列。在您的数据库中,有时会插入表中,而不使用给定表的序列。
我会正确地做到这一点,但肮脏的做法是:
SELECT MAX(id) from tiers;
ALTER SEQUENCE tiers_id_seq RESTART WITH 10000000000; -- or perhaps max value with some rounding upwards
Postgres 中是否有一些选项可以在正确插入后设置序列值?
是的。正如您可能已经猜到的,简单的实现是使用触发器。这种方式在大多数情况下都有效,但与任何触发器一样,它会影响性能。当然,另一种选择是您使用的:将其设置为默认值。在这两种情况下,您都让数据库处理它,但不幸的是,这不是正确的方法。
事实上,MySQL 有一个 AUTOINCRMENT 类型,它可以完全满足您的需求并且可以在本机运行。那么 PostGres 呢?是的,确实如此,但它不是一种专用类型。在 PG 中,它们被称为“串行类型”:SMALLSERIAL、SERIAL 和 BIGSERIAL。 PG 文档甚至指出:
数据类型smallserial、serial和bigserial不是真正的类型, 但仅仅是创建唯一标识符的符号方便 列(类似于某些支持的 AUTO_INCRMENT 属性 其他数据库)。几乎当然,文档还指出这
就是你所做的:
CREATE TABLE 表名 ( 名称 SERIAL );serial相当于指定:
CREATE SEQUENCE 表名_列名_seq AS 整数;创建表 表名 ( colname 整数 NOT NULL DEFAULT nextval('tablename_colname_seq') ); ALTER SEQUENCE tablename_colname_seq 拥有 tablename.colname;当然,使用
类型的语法糖来执行此操作将确保 PG 在幕后处理所需的所有内容,而无需您担心。 您正在使用
id bigint NOT NULL DEFAULT nextval('tiers_id_seq'::regclass)
。
我还建议您阅读this问题及其接受的答案,作为 regclass 的复习:What does regclass Mean in Postgresql? 新方式
identity 列。 当然,无论哪种方式,你的序列都需要“调整”到正确的值。请记住,如果任何脚本强制插入 id,
GENERATED BY DEFAULT
将
try允许它,并且稍后当它们自动生成时您可能会遇到问题。最好的选择是在修复序列后使用
GENERATED ALWAYS
,然后更改脚本以不触及 id 列。