postgresql 重复键违反唯一约束

Posted

技术标签:

【中文标题】postgresql 重复键违反唯一约束【英文标题】:postgresql duplicate key violates unique constraint 【发布时间】:2011-05-25 19:15:42 【问题描述】:

您好,我有一个问题,我知道这已多次发布,但我没有找到问题的答案。问题是我有一个表和一个列“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)

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

【问题讨论】:

显示插入数据的代码;拥有主键已经强制一个唯一的约束,所以你不需要添加它。 【参考方案1】:

This article explains您的序列可能不同步,您必须手动使其恢复同步。

文章摘录,以防 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);

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

【讨论】:

对我来说,我不知道如何获得“the_primary_key_sequence”——您可以在 this other answer 中看到,您可以使用一种名为 pg_get_serial_sequence('table_name', 'field_name') 的方法来使其工作。 果然解决了这个问题 - 任何人都知道这些是如何不同步的吗? SELECT setval('the_primary_key_sequence', (SELECT MAX(the_primary_key) FROM the_table)+1); 可能不完全正确。如果 MAX(the_primary_key) 值例如为 9 且 nextval 项为 9,则足以运行 SELECT setval('the_primary_key_sequence', (SELECT MAX(the_primary_key) FROM the_table));。这将自动产生 nextval 序列增量。如果您添加 +1,结果将跳过一个序列。真棒答案!帮我解决了这个问题! 如果对如何调用序列有疑问,请调用 SELECT c.relname FROM pg_class c WHERE c.relkind = 'S';如果您使用多个模式,请记住每个模式的序列都是唯一的,因此除非您的序列在公共模式中,否则您需要调用 SELECT nextval('schema.sequence_name');得到它 ^ 要回答我自己的问题,您可以这样做:\d "table_name";【参考方案2】:

简介

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

案例

我的情况如下:有一个使用应用程序填充数据的表格。现在必须通过 SQL 手动插入一个新条目。之后序列不同步,无法通过应用插入更多记录。

解决方案

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

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

假设所有示例,Foo 是表名,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);

【讨论】:

这对我有用。导入表时出现了一些故障,导致 id_seq 不同步。这个解决方案为我解决了这个问题。 是否有可以动态执行此操作的脚本?用所有表替换 Foo ,用所有主键替换 Foo_id 我收到了currval of sequence "request_request_id_seq" is not yet defined in this session,不得不使用SELECT last_value FROM <sequence_name>;【参考方案3】:

对于将来的搜索,请使用 ON CONFLICT DO NOTHING。

【讨论】:

如果我已经在另一个不是主键的列上发生冲突了怎么办 您可以指定列名、索引或约束名。示例:ON CONFLICT (column_name) 参考:postgresql.org/docs/13/sql-insert.html【参考方案4】:

Referrence - 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 才能在服务器上运行它

【讨论】:

谢谢。这挽救了我的生命+时间。只需python manage.py sqlsequencereset app_name | python manage.py dbshell 就完成了。【参考方案5】:

主键已经在保护您免于插入重复值,正如您遇到该错误时所遇到的那样。不需要添加另一个唯一约束。

“重复键”错误告诉您工作未完成,因为它会产生重复键,而不是它发现已提交到表的重复键。

【讨论】:

【参考方案6】:

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

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

【讨论】:

【参考方案7】:

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

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);

祝大家好运!

【讨论】:

【参考方案8】:

如果表是由 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
    )

【讨论】:

【参考方案9】:

我遇到了同样的问题。这是因为我的关系类型。我有一个与州和城市有关的表格财产。因此,起初我将财产与州建立为 OneToOne 的关系,对于城市也是如此。我有同样的错误“重复键违反唯一约束”。这意味着:我只能拥有与一个州和城市相关的一项财产。但这没有意义,因为一个城市可以有多个属性。所以问题是关系。关系应该是多对一。一个城市的许多物业

【讨论】:

【参考方案10】:

用于 Django 的编程解决方案。基于Paolo Melchiorre's answer,我wrote a chunk as a function在任何.save()之前被调用

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)

【讨论】:

【参考方案11】:

我有类似的问题,但我通过删除我的 Postgresql 中的所有外键解决了它

【讨论】:

以上是关于postgresql 重复键违反唯一约束的主要内容,如果未能解决你的问题,请参考以下文章

Django 重复键值违反唯一约束错误模型表单

尽管存在检查,“重复键值违反了唯一约束”

将数据从Json文件加载到Postgresql会导致:错误“重复键值违反唯一约束 - 已存在”。

如何更新 postgreSQL 唯一键约束

IntegrityError:重复键值违反唯一约束

Golang:重复键值违反唯一约束