修复表结构以避免出现“错误:重复的键值违反唯一约束”


15

我有这样创建的表:

--
-- Table: #__content
--
CREATE TABLE "jos_content" (
  "id" serial NOT NULL,
  "asset_id" bigint DEFAULT 0 NOT NULL,
   ...
  "xreference" varchar(50) DEFAULT '' NOT NULL,
  PRIMARY KEY ("id")
);

稍后,插入一些指定ID的行:

INSERT INTO "jos_content" VALUES (1,36,'About',...)

稍后,将插入一些没有id的记录,它们将失败并显示错误: Error: duplicate key value violates unique constraint

显然,id被定义为一个序列:

在此处输入图片说明

每个失败的插入都会增加序列中的指针,直到它递增到不再存在的值并且查询成功为止。

SELECT nextval('jos_content_id_seq'::regclass)

表定义有什么问题?解决此问题的明智方法是什么?


在PostgreSQL中,如果列名和表名都是小写的,则不需要用引号引起来。
罗德里戈2015年

Answers:


19

您的表定义没有问题。
(除了帽子,我将使用jos_content_id或代替非描述性的列名id
而且我可能会使用text而不是varchar(50)

您的INSERT陈述就是问题。

id栏定义为时serial,您不应插入的手动值id。这些可能会与关联序列中的下一个值发生冲突。

提供目标列的显式列表(这对于持久化INSERT语句几乎总是一个好主意),并完全省略串行列

INSERT INTO jos_content(asset_id, some_column, ...)
VALUES (36,'About',...);

如果您需要立即自动生成的列的值,请使用以下RETURNING子句

INSERT ...
RETURNING id;  -- possibly more

有关SO的此相关答案中的更多详细信息:

如果您在手动输入serial列可能发生冲突后,请将您的序列电流最大值id,以解决一次

SELECT setval('jos_content_id_seq', max(id))
FROM   jos_content;

where jos_content_id_seq是拥有的序列的默认名称jos_content.id,您已经在default列中找到了该名称。似乎xhzt8_content_id_seq在您的情况下;


更新: SO上出现了类似的问题,我想出了一个新的解决方案:


文字不是比varchar(50)慢吗?
罗德里戈

2
@Rodrigo:不在Postgres中。上面有一个链接以提供更多说明:dba.stackexchange.com/a/21496/3684。还是这里 dba.stackexchange.com/a/89433/3684
Erwin Brandstetter

在这里进行的最后一次测试< depesz.com/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text >使我确信varchar(n)在大多数方便大小限制的字段上都更快(人们名称,电子邮件,地址,物种名称等)。看来,如果您不检查长度,文本速度会更快(或相同)。
罗德里戈
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.