Postgres 什么时候检查唯一约束?
When does Postgres check unique constraints?
我有一个列 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.
显然,如果 sort_order
值在更新前是唯一的,那么更新后它们仍然是唯一的。为什么是这样?
相同的语句在 Oracle 和 MS SQL 上工作正常,但在 MySQL 和 SQLite 上也失败。
这是 SQL fiddle 的完整设置代码:
DROP TABLE IF EXISTS test;
CREATE TABLE test (
val TEXT,
sort_order INTEGER NOT NULL UNIQUE
);
INSERT INTO test
VALUES ('A', 1), ('B', 2);
Postgres 决定在不同于 SQL 标准建议的时间检查类型 IMMEDIATELY
的约束。
具体来说,SET CONSTRAINTS
的文档指出(强调我的):
NOT NULL and CHECK constraints are always checked immediately when a row is inserted or modified (not at the end of the statement). Uniqueness and exclusion constraints that have not been declared DEFERRABLE are also checked immediately.
Postgres 选择使用导致 sort_order
和 IMMEDIATELY 的临时冲突的计划执行此查询失败。请注意,这意味着 对于相同的架构和相同的数据,相同的查询可能会成功或失败,具体取决于执行计划。
您必须制定约束 DEFERRABLE
或 DEFERRABLE INITIALLY DEFERRED
,这会将约束的验证延迟到事务结束或语句 SET CONSTRAINTS ... IMMEDIATE
被执行。
来自@HansGinzel 评论的附录:
for COPY
, it seems, that (even IMMEDIATE) constraints are tested after all data are COPYied.
我有一个列 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.
显然,如果 sort_order
值在更新前是唯一的,那么更新后它们仍然是唯一的。为什么是这样?
相同的语句在 Oracle 和 MS SQL 上工作正常,但在 MySQL 和 SQLite 上也失败。
这是 SQL fiddle 的完整设置代码:
DROP TABLE IF EXISTS test;
CREATE TABLE test (
val TEXT,
sort_order INTEGER NOT NULL UNIQUE
);
INSERT INTO test
VALUES ('A', 1), ('B', 2);
Postgres 决定在不同于 SQL 标准建议的时间检查类型 IMMEDIATELY
的约束。
具体来说,SET CONSTRAINTS
的文档指出(强调我的):
NOT NULL and CHECK constraints are always checked immediately when a row is inserted or modified (not at the end of the statement). Uniqueness and exclusion constraints that have not been declared DEFERRABLE are also checked immediately.
Postgres 选择使用导致 sort_order
和 IMMEDIATELY 的临时冲突的计划执行此查询失败。请注意,这意味着 对于相同的架构和相同的数据,相同的查询可能会成功或失败,具体取决于执行计划。
您必须制定约束 DEFERRABLE
或 DEFERRABLE INITIALLY DEFERRED
,这会将约束的验证延迟到事务结束或语句 SET CONSTRAINTS ... IMMEDIATE
被执行。
来自@HansGinzel 评论的附录:
for
COPY
, it seems, that (even IMMEDIATE) constraints are tested after all data are COPYied.