Postgreql 重复键违反了唯一约束

我有一个问题,我知道这是张贴了很多次,但我没有找到一个答案,我的问题。问题是,我有一个表和一个列“ id”,我希望它是唯一的数字,就像正常情况一样。这种类型的列是串行的,每次插入后的下一个值来自一个序列,所以看起来一切正常,但有时仍然显示这个错误。我不知道为什么。在文档中,它说这个顺序是万无一失的,并且总是有效的。如果我向该列添加一个 UNIQUE 约束,它会有帮助吗?我以前在 Postres 上工作过很多次,但是这个错误第一次在我身上显现出来。我一切正常,以前从来没有这个问题。您能帮助我找到将来可以用于所有将要创建的表的答案吗?假设我们有这样简单的东西:

CREATE TABLE comments
(
id serial NOT NULL,
some_column text NOT NULL,
CONSTRAINT id_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE interesting.comments OWNER TO postgres;

如果我加上:

ALTER TABLE comments ADD CONSTRAINT id_id_key UNIQUE(id)

是否足够,或者还有其他应该做的事情?

273897 次浏览

来自 http://www.postgresql.org/docs/current/interactive/datatype.html

注意: 在 PostgreSQL 7.3之前,串行隐含 UNIQUE。这不再是自动的。如果希望串行列处于唯一约束或主键中,现在必须指定它,与任何其他数据类型相同。

主键已经在保护您不要插入重复的值,因为当您得到这个错误时,您正在经历这种情况。添加另一个唯一约束不是必须的。

“重复键”错误告诉您,这项工作没有完成,因为它会产生一个重复键,而不是说它发现了一个已经提交给表的重复键。

本文解释了 ,您的序列可能不同步,必须手动使其恢复同步。

如果 URL 发生变化,这篇文章的摘录如下:

如果在尝试将数据插入 PostgreSQL 时收到此消息 资料库:

ERROR:  duplicate key violates unique constraint

这可能意味着表中的主键序列 不知怎么的就不同步了,很可能是因为质量问题 导入过程(或类似的东西) 但似乎您必须手动重置主 从转储文件还原后的键索引。无论如何,要查看 您的值不同步,请运行以下两个命令:

SELECT MAX(the_primary_key) FROM the_table;
SELECT nextval('the_primary_key_sequence');

如果第一个值大于第二个值,则序列为 备份您的 PG 数据库(以防万一) ,然后运行以下命令:

SELECT setval('the_primary_key_sequence', (SELECT MAX(the_primary_key) FROM the_table)+1);

将序列设置为下一个更高的可用值 比序列中任何现有的主键都多。

参考 https://www.calazan.com/how-to-reset-the-primary-key-sequence-in-postgresql-with-django/

我也有同样的问题,试试这个: python manage.py sqlsequencereset table_name

例如:

python manage.py sqlsequencereset auth

您需要在生产设置中运行它(如果有的话) 你需要安装 Postgres 在服务器上运行它

对于未来的搜索,使用 ON 冲突不做任何事。

我也有类似的问题,但是我通过删除 Postgreql 中的所有外键解决了这个问题

介绍

我也遇到了这个问题,@adamo 提出的解决方案基本上是正确的。然而,我必须在细节上投入大量的时间,这就是为什么我现在正在写一个新的答案,以便为其他人节省这些时间。

凯斯

我的情况是这样的: 有一个使用应用程序填充数据的表。现在必须通过 SQL 手动插入一个新条目。之后,该序列不同步,没有更多的记录可以通过应用程序插入。

解决方案

正如@adamo 的回答中提到的,序列必须手动同步。为此,需要序列的名称。对于 Postgres,可以使用命令 PG_GET_SERIAL_SEQUENCE确定序列的名称。大多数示例使用小写表名。在我的例子中,这些表是由 ORM 中间件(如 Hibernate 或 Entity Framework Core 等)创建的,它们的名称都以大写字母开头。

在2004年的一封电子邮件(链接)中,我得到了正确的提示。

(让我们假设对于所有示例,ABC0是表的名称,Foo_id是相关的列。)

命令获取序列名称:

SELECT PG_GET_SERIAL_SEQUENCE('"Foo"', 'Foo_id');

因此,表名必须用双引号括起来,并用单引号括起来。

1. 验证序列不同步

SELECT CURRVAL(PG_GET_SERIAL_SEQUENCE('"Foo"', 'Foo_id')) AS "Current Value", MAX("Foo_id") AS "Max Value" FROM "Foo";

Current Value小于 Max Value时,序列不同步。

2. 更正

SELECT SETVAL((SELECT PG_GET_SERIAL_SEQUENCE('"Foo"', 'Foo_id')), (SELECT (MAX("Foo_id") + 1) FROM "Foo"), FALSE);

在我的情况下,卡拉表脚本是:

CREATE TABLE public."Survey_symptom_binds"
(
id integer NOT NULL DEFAULT nextval('"Survey_symptom_binds_id_seq"'::regclass),
survey_id integer,
"order" smallint,
symptom_id integer,
CONSTRAINT "Survey_symptom_binds_pkey" PRIMARY KEY (id)
)

所以:

SELECT nextval('"Survey_symptom_binds_id_seq"'::regclass),
MAX(id)
FROM public."Survey_symptom_binds";
  

SELECT nextval('"Survey_symptom_binds_id_seq"'::regclass) less than MAX(id) !!!

试着解决这个问题:

SELECT setval('"Survey_symptom_binds_id_seq"', (SELECT MAX(id) FROM public."Survey_symptom_binds")+1);

祝大家好运!

如果表是由 ORM 中间件(如 Hibernate 或 Entity Framework Core 等)创建的,则表名以大写字母开头

SELECT setval('"Table_name_Id_seq"', (SELECT MAX("Id") FROM "Table_name") + 1)
WHERE
NOT EXISTS (
SELECT *
FROM  (SELECT CURRVAL(PG_GET_SERIAL_SEQUENCE('"Table_name"', 'Id')) AS seq, MAX("Id") AS max_id
FROM "Table_name") AS seq_table
WHERE seq > max_id
)

我也有同样的问题。这是因为我的关系类型。我有一个与州和城市都有关的表属性。因此,一开始我有一个从财产到国家的关系,就像 OneToOne 一样,对于城市也是一样。我也犯了同样的错误“重复键违反了唯一约束”。这意味着: 我只能拥有与一个州和城市相关的一处房产。但这没有意义,因为一个城市可以有多个属性。所以问题在于关系。这个关系应该是 ManyToOne。一个城市的许多财产

对于 Django 的程序化解决方案,基于 Paolo Melchiorre 的回答,在任何. save ()之前调用 I 写了一个块作为函数

from django.db import connection
def setSqlCursor(db_table):
sql = """SELECT pg_catalog.setval(pg_get_serial_sequence('"""+db_table+"""', 'id'), MAX(id)) FROM """+db_table+""";"""
with connection.cursor() as cursor:
cursor.execute(sql)

table_name替换为表的实际名称。

  1. 给出表的当前最后一个 id。请注意,下一步。
SELECT MAX(id) FROM table_name;


  1. 根据 postgreql 获取下一个 id 序列。确保这个 id 高于我们从步骤1中得到的当前最大 id
SELECT nextVal('"table_name_id_seq"');
  1. 如果它不高于然后使用这个步骤3来更新下一个序列。
SELECT setval('"table_name_id_seq"', (SELECT MAX(id) FROM table_name)+1);

试试 CLI

这只是一个建议,以加强亚当代码(非常感谢亚当)

SELECT setval('tableName_columnName_seq', (SELECT MAX(columnName) FROM tableName));