我有一个列sort_order
,其上有一个唯一约束。
Postgres 9.5上的以下SQL失败:
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.
显然,如果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);
答案 0 :(得分:5)
Postgres决定在与SQL标准中建议的时间不同的时间检查IMMEDIATELY
类型的约束。
具体来说,SET CONSTRAINTS
州的文件(强调我的):
当插入或修改(不在语句末尾)行时,会立即检查NOT NULL和CHECK约束。还会立即检查尚未声明为DEFERRABLE的唯一性和排除约束。
Postgres选择使用导致sort_order
暂时冲突且立即失败的计划执行此查询。请注意,对于相同的架构和相同的数据,表示相同的查询可能有效或失败,具体取决于执行计划。
您必须制定约束DEFERRABLE
或DEFERRABLE INITIALLY DEFERRED
,这会延迟约束的验证,直到事务结束或执行语句SET CONSTRAINTS ... IMMEDIATE
为止