如何彻底解决 Potgresql 自动增量违反唯一约束的问题

问题描述 投票:0回答:2

如何解决 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)
);
auto-increment unique-constraint postgresql-14
2个回答
0
投票

我猜想,您已经将一些带有 ID 的行导入/插入到数据库中,而没有改变顺序。在postgresql中,没有“自动增量”列类型。只有整数类型和序列(其他实体)的列,可以为您提供增量序列。在您的数据库中,有时会插入表中,而不使用给定表的序列。

我会正确地做到这一点,但肮脏的做法是:

SELECT MAX(id) from tiers;
ALTER SEQUENCE tiers_id_seq RESTART WITH 10000000000; -- or perhaps max value with some rounding upwards

0
投票

Postgres 中是否有一些选项可以在正确插入后设置序列值?

是的。正如您可能已经猜到的,简单的实现是使用触发器。这种方式在大多数情况下都有效,但与任何触发器一样,它会影响性能。当然,另一种选择是您使用的:将其设置为默认值。在这两种情况下,您都让数据库处理它,但不幸的是,这不是正确的方法。

老方法

事实上,MySQL 有一个 AUTOINCRMENT 类型,它可以完全满足您的需求并且可以在本机运行。那么 PostGres 呢?是的,确实如此,但它不是一种专用类型。在 PG 中,它们被称为“串行类型”:SMALLSERIAL、SERIAL 和 BIGSERIAL。 PG 文档甚至指出:

数据类型smallserial、serial和bigserial不是真正的类型, 但仅仅是创建唯一标识符的符号方便 列(类似于某些支持的 AUTO_INCRMENT 属性 其他数据库)。

当然,文档还指出这
几乎

就是你所做的:

CREATE TABLE 表名 ( 名称 SERIAL );

相当于指定:

CREATE SEQUENCE 表名_列名_seq AS 整数;创建表 表名 ( colname 整数 NOT NULL DEFAULT nextval('tablename_colname_seq') ); ALTER SEQUENCE tablename_colname_seq 拥有 tablename.colname;

当然,使用
serial

类型的语法糖来执行此操作将确保 PG 在幕后处理所需的所有内容,而无需您担心。 您正在使用

id bigint NOT NULL DEFAULT nextval('tiers_id_seq'::regclass)

我还建议您阅读

this

问题及其接受的答案,作为 regclass 的复习:What does regclass Mean in Postgresql? 新方式

如果您使用 PG 10 或更高版本,您可以使用 Oracle 也使用的新方法:

an

identity 当然,无论哪种方式,你的序列都需要“调整”到正确的值。请记住,如果任何脚本强制插入 id,

GENERATED BY DEFAULT

try
允许它,并且稍后当它们自动生成时您可能会遇到问题。最好的选择是在修复序列后使用 GENERATED ALWAYS,然后更改脚本以不触及 id 列。
    

© www.soinside.com 2019 - 2024. All rights reserved.