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 重复键违反唯一约束的主要内容,如果未能解决你的问题,请参考以下文章