在PostgreSQL中更新非空和唯一约束的列的特例

时间:2010-07-20 22:10:02

标签: sql postgresql constraints unique-constraint

这是一个玩具示例,说明了PostgreSQL中的一个真正的问题。以下示例使用的是PostgreSQL 8.4.3服务器,但我怀疑其他版本也有同样的问题。

鉴于下表:

=> create table tmp_foo (foo boolean not null unique, bar boolean not null unique);
=> insert into tmp_foo (foo, bar) values (true, true), (false, false);
=> select * from tmp_foo;
 foo | bar 
-----+-----
 t   | t
 f   | f

可以将表修改为如下所示:

=> select * from tmp_foo;
 foo | bar 
-----+-----
 t   | f
 f   | t

不删除行或修改表架构?这样:

=> update tmp_foo set bar = not bar;
ERROR:  duplicate key value violates unique constraint "tmp_foo_bar_key"

不起作用。

如果允许删除,请执行以下操作:

=> create temp table tmp_foo_2 as select * from tmp_foo;
=> update tmp_foo_2 set bar = not bar;
=> delete from tmp_foo;
=> insert into tmp_foo select * from tmp_foo_2;

的工作原理。对于这个例子来说,这不是最简单的解决方案,但它很容易推广到更复杂的例子。

1 个答案:

答案 0 :(得分:3)

这样做需要可延迟的唯一约束。

每列中的行数尽可能多。因此,要改变任何行,要么某些行必须暂时违反唯一约束,要么必须删除某些行以避免违反约束。可延迟的唯一约束让我们做前者 - 临时违规(在交易中)。

如果您遵循这一点,听起来是正确的,那么您的问题的答案取决于Postgres版本。

Postgres仅限8.4 allows deferral of foreign key constraints。推论是不能推迟独特的约束。

Postgres 9.0 beta理论上提供了可延迟的唯一约束。我自己没有尝试过,但是这个功能已经很长时间了,所以我敢打赌他们在决定实现它时就做对了。

以下是关于9.0 unique indicesSET CONSTRAINTS的两个相关文档。正如您在后一个链接中所看到的,在9.0文档中通过SET CONSTRAINTS明确列出了对延迟支持的唯一约束。我还没有探索过这个新功能,我不能保证语义正是你所需要的。但它似乎只是那件事。