尝试使用部分索引来升级表

时间:2017-05-30 16:19:10

标签: postgresql upsert postgresql-9.5

所以我的表格结构类似于:

CREATE TABLE x (
    id SERIAL,
    a character varying(1024) NOT NULL,
    b character varying(2048),
    c character varying(1024)
);

CREATE UNIQUE INDEX uniq_x_a ON x USING btree (a) WHERE (b IS NULL);
CREATE UNIQUE INDEX uniq_x_a_b ON x USING btree (a, b) WHERE (b IS NOT NULL);

现在我将此实例升级到9.5,并希望使用ON CONFLICT DO UPDATE

执行此

INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c1');
INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c2');

现在给了我

ERROR:  duplicate key value violates unique constraint "uniq_x_a_b"
DETAIL:  Key (a, b)=(hello, there) already exists.

然后当我做

INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c4') 
ON CONFLICT ON CONSTRAINT uniq_x_a_b DO UPDATE SET c = excluded.c;

我得到了

ERROR:  constraint "uniq_x_a_b" for table "x" does not exist

我不明白,我违反了不存在的约束条件?有人有提示吗?

修改

根据我的建议我添加了

ALTER TABLE x ADD CONSTRAINT uniq_x_a_b_constraint UNIQUE (a, b);

所以现在这适用于以下情况:

INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c3') 
ON CONFLICT ON CONSTRAINT uniq_x_a_b_constraint DO UPDATE SET c = excluded.c;

失败了
INSERT INTO x (a, b, c) VALUES ('hello', NULL, 'c3') 
ON CONFLICT ON CONSTRAINT uniq_x_a_b_constraint DO UPDATE SET c = excluded.c;

ERROR:  duplicate key value violates unique constraint "uniq_x_a"
DETAIL:  Key (a)=(hello) already exists.

我无法单独在列a上添加唯一约束,因为它是ab的组合,应该是唯一的。似乎也不可能在行的子集上构建约束,就像创建索引一样。

1 个答案:

答案 0 :(得分:2)

这里有几件事情在发挥作用。

  1. 创建唯一索引不会自动创建唯一约束(尽管在尝试插入重复记录时,错误消息中使用了术语constraint)。另一方面,添加唯一约束将自动在列或列组上创建唯一的B树索引(请参阅此doc)。

  2. 与常规索引不同,无法使用部分索引添加约束:

    ALTER TABLE x ADD CONSTRAINT uniq_x_a_constraint UNIQUE USING INDEX uniq_x_a;
    ERROR:  "uniq_x_a" is a partial index ...
    DETAIL:  Cannot create a primary key or unique constraint using such an index.
    
  3. 本质上,您需要在(a, b)上创建一个单独的唯一约束(与部分索引无关),以便以预期的方式使ON CONFLICT起作用。

    [UPDATE]

    即使a和b的组合是唯一的,ON CONFLICT也不会看到强制唯一性的任何有效约束:

    INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c4') 
    ON CONFLICT (a, b) DO UPDATE SET c = excluded.c;
    ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
    

    现在,如果您添加约束,ON CONFLICT (a, b)ON CONFLICT ON CONSTRAINT都可以使用:

    ALTER TABLE x ADD CONSTRAINT uniq_x_a_b_constraint UNIQUE (a, b);
    
    INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c4') 
    ON CONFLICT (a, b) DO UPDATE SET c = excluded.c;
    
    INSERT INTO x (a, b, c) VALUES ('hello', 'there', 'c5') 
    ON CONFLICT ON CONSTRAINT uniq_x_a_b_constraint DO UPDATE SET c = excluded.c;