Postgres何时检查唯一约束?

blu*_*ubb 5 postgresql unique-constraint

我有一列sort_order具有唯一约束的列。以下SQL在Postgres 9.5上失败:

UPDATE test
SET sort_order = sort_order + 1;

-- [23505] ERROR: duplicate key value violates unique constraint "test_sort_order_key"
--   Detail: Key (sort_order)=(2) already exists.
Run Code Online (Sandbox Code Playgroud)

显然,如果sort_order值在更新之前是唯一的,则在更新之后它们仍将是唯一的。为什么是这样?

相同的语句在Oracle和MS SQL上工作正常,但在MySQL和SQLite上失败。


这是SQL小提琴的完整设置代码:

DROP TABLE IF EXISTS test;
CREATE TABLE test (
  val        TEXT,
  sort_order INTEGER NOT NULL UNIQUE
);

INSERT INTO test
VALUES ('A', 1), ('B', 2);
Run Code Online (Sandbox Code Playgroud)

blu*_*ubb 6

Postgres决定IMMEDIATELY在与SQL标准建议不同的时间检查类型的约束。

具体来说,SET CONSTRAINTS各州的文件(重点是我的):

当插入或修改一行时(不在语句末尾),始终会立即检查NOT NULL和CHECK约束。还可以立即检查尚未声明为DEFERRABLE的唯一性和排除约束。

Postgres选择使用会导致临时冲突sort_order立即失败的计划执行此查询。请注意,这意味着对于相同的架构和相同的数据,根据执行计划,相同的查询可能会工作或失败。

您必须制作约束DEFERRABLEDEFERRABLE INITIALLY DEFERRED,这会延迟对约束的验证,直到事务结束或SET CONSTRAINTS ... IMMEDIATE执行语句为止。