postgresql重复键违反了唯一约束

red*_*red 24 postgresql

嗨,我有一个问题,我知道这是多次发布,但我没有找到我的问题的答案.问题是我有一个表和一列"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;
Run Code Online (Sandbox Code Playgroud)

如果我添加:

ALTER TABLE comments ADD CONSTRAINT id_id_key UNIQUE(id)
Run Code Online (Sandbox Code Playgroud)

是否应该或是否还有其他事情要做?

ada*_*amo 63

本文解释了您的序列可能不同步,您必须手动将其重新同步.

如果URL更改,则摘自文章:

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

ERROR:  duplicate key violates unique constraint
Run Code Online (Sandbox Code Playgroud)

这可能意味着您正在使用的表中的主键序列以某种方式变得不同步,可能是因为大量导入过程(或沿着这些行的某些内容).称之为"设计错误",但似乎必须在从转储文件恢复后手动重置主键索引.无论如何,要查看您的值是否不同步,请运行以下两个命令:

SELECT MAX(the_primary_key) FROM the_table;   
SELECT nextval('the_primary_key_sequence');
Run Code Online (Sandbox Code Playgroud)

如果第一个值高于第二个值,则序列不同步.备份PG数据库(以防万一),然后运行thisL

SELECT setval('the_primary_key_sequence', (SELECT MAX(the_primary_key) FROM the_table)+1);
Run Code Online (Sandbox Code Playgroud)

这会将序列设置为下一个可用值,该值高于序列中任何现有的主键.

  • 对我来说,我不知道如何获得"the_primary_key_sequence" - 您可以在[这个其他答案](/sf/answers/1276316471/)中看到您可以使用名为`pg_get_serial_sequence的方法( 'table_name','field_name')`让它工作. (8认同)
  • `SELECT setval('the_primary_key_sequence', (SELECT MAX(the_primary_key) FROM the_table)+1);` 可能不完全正确。例如,如果 MAX(the_primary_key) 值为 9 并且 nextval item 为 9,则运行`SELECT setval('the_primary_key_sequence', (SELECT MAX(the_primary_key) FROM the_table));`就足够了。这将自动产生 nextval 序列增量。如果添加 +1,结果将是跳过一个序列。很棒的答案!帮我解决了这个问题! (4认同)
  • ^ 要回答我自己的问题,您可以这样做来找到它:`\d "table_name";` (3认同)
  • 你好。如果查询对任何人都没有意义,让我举一个例子希望能有所帮助:我的表显示 sid 作为主键,所以我使用此查询来检查最大主键: `MAX(sid) FROM schema_name.table_name ;` -sid 是我表中的一列,代表主键。-schema_name 是我的表所在的架构。-table_name 是引发重复键错误的表的名称。这就是我运行来检查主键序列的下一个值:`SELECT nextval(pg_get_serial_sequence('schema_name.table_name', 'sid'));` 我希望这有某种帮助。 (3认同)
  • 果然这修复了它 - 任何人都对这些如何不同步有任何见解? (2认同)
  • 需要明确的是,命令是:`SELECT setval(pg_get_serial_sequence('table', 'id'), (SELECT MAX(id) FROM table)+1);` 谢谢@user (2认同)
  • @PV,您还可以通过以下方式获取“the_primary_key_sequence”:“SELECT pg_get_serial_sequence('the_table', 'the_primary_key')” (2认同)
  • @Papooch http://web.archive.org/web/20140328105619/http://hcmc.uvic.ca/blogs/index.php?blog=22&p=8105&more=1&c=1&tb=1&pb=1 (2认同)

Sal*_*man 29

将 替换table_name为您的实际表名称。

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

Run Code Online (Sandbox Code Playgroud)
  1. 根据postgresql获取下一个id序列。确保此 id 高于我们从步骤 1 获得的当前最大 id
SELECT nextVal('"table_name_id_seq"');
Run Code Online (Sandbox Code Playgroud)
  1. 如果不高于则使用步骤 3 更新下一个序列。
SELECT setval('"table_name_id_seq"', (SELECT MAX(id) FROM table_name)+1);
Run Code Online (Sandbox Code Playgroud)


Som*_*ing 15

介绍

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

案件

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

解决方案

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

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

让我们假设所有示例,即Foo表的名称和Foo_id相关列。

获取序列名称的命令:

SELECT PG_GET_SERIAL_SEQUENCE('"Foo"', 'Foo_id');
Run Code Online (Sandbox Code Playgroud)

所以,表名必须用双引号括起来,用单引号括起来。

1. 验证序列是否不同步

SELECT CURRVAL(PG_GET_SERIAL_SEQUENCE('"Foo"', 'Foo_id')) AS "Current Value", MAX("Foo_id") AS "Max Value" FROM "Foo";
Run Code Online (Sandbox Code Playgroud)

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

2. 更正

SELECT SETVAL((SELECT PG_GET_SERIAL_SEQUENCE('"Foo"', 'Foo_id')), (SELECT (MAX("Foo_id") + 1) FROM "Foo"), FALSE);
Run Code Online (Sandbox Code Playgroud)

  • 我收到“序列“request_request_id_seq”的当前值尚未在此会话中定义”,并且必须使用“SELECT last_value FROM <sequence_name>;” (5认同)

Kev*_*val 6

参考 - 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
Run Code Online (Sandbox Code Playgroud)

您需要在生产设置中运行它(如果有)并且您需要安装 Postgres 才能在服务器上运行它

  • 谢谢。这既救了我的命又救了我的时间。只是`python manage.py sqlsequencereset app_name | python manage.py dbshel​​l` 就完成了。 (3认同)

raf*_*kar 6

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

  • 您可以指定列名称、索引或约束名称。示例:ON CONFLICT (column_name) 参考:https://www.postgresql.org/docs/13/sql-insert.html (2认同)

Ste*_*nne 5

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

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


sta*_*ker 1

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

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