PostgreSQL 中更新具有非空和唯一约束的列的特殊情况

发布于 2024-09-10 09:07:02 字数 870 浏览 12 评论 0原文

这是一个说明 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;

有效。对于此示例来说,它不是最简单的解决方案,但它可以轻松推广到更复杂的示例。

This is a toy example that illustrates a real problem in PostgreSQL. The below examples are using a PostgreSQL 8.4.3 server, but I suspect other versions have the same problem.

Given the following table:

=> 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

can the table be modified to look like this:

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

without deleting rows or modifying the table schema? This:

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

does not work.

If deletes are allowed, this:

=> 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;

works. It is not the simplest solution for this example, but it is easily generalizable to more complex examples.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

固执像三岁 2024-09-17 09:07:02

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

我们在每列中拥有尽可能多的行唯一值。因此,要改变任何行,要么某些行必须暂时违反唯一约束,要么必须删除某些行以避免违反约束。可延迟的唯一约束让我们可以执行前者——临时违规(在事务内)。

如果您到目前为止,并且听起来是正确的,那么您问题的答案取决于 Postgres 版本。

仅 Postgres 8.4 允许推迟外键约束。推论是独特的约束不能被推迟。

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

以下是关于 9.0 的两部分相关文档 唯一索引< /a> 和 设置约束< /a>.正如您在后一个链接中所看到的,在 9.0 文档中,通过 SET CONSTRAINTS 明确列出了支持延迟的唯一约束。我还没有探索这个新功能,我不能保证语义正是您所需要的。但这似乎只是事情。

Doing this requires deferrable unique constraints.

We have as many rows as possible unique values in each column. So to mutate any row, either some rows must temporarily violate a unique constraint, or some row(s) must be deleted to avoid violating the constraint. Deferrable unique constraints let us do the former -- temporary violation (inside a transaction).

If you follow this far, and it sounds right, then the answer to your question depends on the Postgres version.

Postgres up to 8.4 only allows deferral of foreign key constraints. The corollary is that unique constraints cannot be deferred.

Postgres 9.0 betas theoretically offer deferrable unique constraints. I haven't tried it myself, but this feature has been a long time coming, so I'd bet they got it right when they decided to implement it.

Here are two morsels of relevant documentation on 9.0's unique indices and SET CONSTRAINTS. As you can see in the latter link, unique constraints are explicitly listed as supported for deferral via SET CONSTRAINTS in the 9.0 documentation. I haven't explored this new feature yet and I can't guarantee that the semantics are exactly what you need. But it seems like just the thing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文