持久的"唯一约束违规"插入时在空表上

时间:2016-02-10 10:36:16

标签: sql postgresql unique-constraint

我们假设我正在管理一个简单的表格。此外,每个用户可以间接创建每行的副本并自行修改。

这是我的设置:

-- the original table
CREATE TABLE test
(
    id integer PRIMARY KEY,
    a integer,
    b integer NOT NULL,
    c integer
);

-- the table holding a modified copy of the former table
CREATE TABLE test_copy
(
    copy_position integer NOT NULL, -- some additional data attached to the copy
    id integer PRIMARY KEY REFERENCES test(id), -- the id of the copied row
    a integer,
    b integer NOT NULL,
    c integer
);

-- some sample data
INSERT INTO test VALUES (1, 4, 4, 4), (2, 7, 3, 2), (3, 72, 23, 7), (4, 11, 22, 33);

我必须创建一个函数,该函数复制test表中的现有行。但是,以下声明可能会失败:

INSERT INTO test_copy(copy_position, id, a, b, c)
    (SELECT 666, 3, t.a, t.b, t.c
        FROM test AS t);

发出以下错误:

ERROR:  duplicate key value violates unique constraint "test_copy_pkey"
DETAIL:  Key (id)=(3) already exists.

test_copy表格完全为空。前一个语句是唯一为表提供任何行的INSERT语句,但它以某种方式违反了唯一约束。在没有SELECT子查询的情况下手动插入值将成功执行。经过几个小时的研究,我已经没有想法可能是错误的原因,我觉得这个问题的解决方案必须非常简单。我正在使用PostgreSQL 9.4。

2 个答案:

答案 0 :(得分:1)

您需要为每条记录创建一个新ID。

而不是

INSERT INTO test_copy(copy_position, id, a, b, c)
    (SELECT 666, 3, t.a, t.b, t.c
        FROM test AS t);

对测试中存在的每条记录始终使用id 3。

如果id类型为autoincrement,请尝试使用以下代码。

INSERT INTO test_copy(copy_position, a, b, c)
    (SELECT 666, t.a, t.b, t.c
        FROM test AS t);

在这种情况下,您将丢失原始ID。如果您需要保留原始ID,则需要使用以下内容更改表结构:

CREATE TABLE test_copy
(
    copy_position integer NOT NULL, -- some additional data attached to the copy
    id integer PRIMARY KEY autoincrement,
    original_id FOREIGN KEY REFERENCES test(id), -- the id of the copied row
    a integer,
    b integer NOT NULL,
    c integer
);

,插入变为:

INSERT INTO test_copy(copy_position, original_id, a, b, c)
        (SELECT 666, t.id, t.a, t.b, t.c
            FROM test AS t);

答案 1 :(得分:1)

嗯,问题是一个完整的非事件。在@a_horse_with_no_name in the comments部分发布之后的前两分钟已经回复了(谢谢你)并且问题本身几乎是一个菜鸟错误。

我完全忘记了WHERE子查询中的SELECT子句。它应该写成如下:

INSERT INTO test_copy(copy_position, id, a, b, c)
    (SELECT 666, t.id, t.a, t.b, t.c
        FROM test AS t WHERE t.id = 3);

这就是这个问题。