我需要在列上强制执行唯一性,但仅当其他列为true时才需要。例如:
create temporary table test(id serial primary key, property character varying(50), value boolean);
insert into test(property, value) values ('a', false);
insert into test(property, value) values ('a', true);
insert into test(property, value) values ('a', false);
我用条件索引强制执行唯一性:
create unique index on test(property) where value = true;
到目前为止,当我尝试更改值设置为true的行时,问题就出现了。如果我这样做,它可以工作:
update test set value = new_value from (select id, id=3 as new_value from test where property = 'a')new_test where test.id = new_test.id
但是当我这样做时却不会这样做:
update test set value = new_value from (select id, id=1 as new_value from test where property = 'a')new_test where test.id = new_test.id
我得到了:
ERROR: duplicate key value violates unique constraint "test_property_idx"
DETAIL: Key (property)=(a) already exists.
********** Error **********
ERROR: duplicate key value violates unique constraint "test_property_idx"
SQL state: 23505
Detail: Key (property)=(a) already exists.
基本上,如果值为true的行的主键值大于当前行的值,则它可以正常运行。关于如何规避它的任何想法?
我当然能做到:
update test set value = false where property='a';
update test set value = true where property = 'a' and id = 1;
但是,我正在从节点运行这些查询,最好只运行一个查询。
我正在使用Postgres 9.5
答案 0 :(得分:3)
你的问题是UPDATE
statements cannot have an ORDER BY
clause in SQL(它可能在某些RDBMS中,但在PostgreSQL中却没有。)
通常的解决方案是使约束可以推迟。但是你使用了一个部分唯一索引&索引不能声明为可延迟的。
使用exclusion constraint代替:它们是唯一约束的推广&也可以是部分的。
ALTER TABLE test
ADD EXCLUDE (property WITH =) WHERE (value = true)
DEFERRABLE INITIALLY DEFERRED;