jcr*_*vao 16 postgresql index transaction unique-constraint
查看用于 alter table 的 postgres 文档,似乎可以将常规约束标记为DEFERRABLE
(更具体地说,INITIALLY DEFERRED
,这是我感兴趣的)。
索引也可以与约束相关联,只要:
索引不能有表达式列,也不能是部分索引
这让我相信目前没有办法拥有一个具有条件的唯一索引,例如:
CREATE UNIQUE INDEX unique_booking
ON public.booking
USING btree
(check_in, check_out)
WHERE booking_status = 1;
Run Code Online (Sandbox Code Playgroud)
是INITIALLY DEFERRED
,意思是,唯一性“约束”只会在交易结束时进行验证(如果SET CONSTRAINTS ALL DEFERRED;
使用)。
我的假设是否正确,如果正确,有什么方法可以实现预期的行为?
谢谢
ype*_*eᵀᴹ 18
索引不能被推迟——不管它是UNIQUE
与否,部分与否,只是一个UNIQUE
约束。其他类型的约束 ( FOREIGN KEY
, PRIMARY KEY
, EXCLUDE
) 也是可延迟的 - 但不是CHECK
约束。
所以唯一的部分索引(及其实现的隐式约束)将在每个语句(实际上在当前实现中的每一行插入/更新之后)进行检查,而不是在事务结束时。
如果您想将此约束实现为可延迟,您可以做的是在设计中再添加一个表。像这样的东西:
CREATE TABLE public.booking_status
( booking_id int NOT NULL, -- same types
check_in timestamp NOT NULL, -- as in
check_out timestamp NOT NULL, -- booking
CONSTRAINT unique_booking
UNIQUE (check_in, check_out)
DEFERRABLE INITIALLY DEFERRED,
CONSTRAINT unique_booking_fk
FOREIGN KEY (booking_id, check_in, check_out)
REFERENCES public.booking (booking_id, check_in, check_out)
DEFERRABLE INITIALLY DEFERRED
) ;
Run Code Online (Sandbox Code Playgroud)
使用这种设计并假设booking_status
只有 2 个可能的选项(0 和 1),您可以将其完全删除booking
(如果在 处有一行booking_status
,则为 1,否则为 0)。
另一种方法是(ab)使用EXCLUDE
约束:
ALTER TABLE booking
ADD CONSTRAINT unique_booking
EXCLUDE
( check_in WITH =,
check_out WITH =,
(CASE WHEN booking_status = 1 THEN TRUE END) WITH =
)
DEFERRABLE INITIALLY DEFERRED ;
Run Code Online (Sandbox Code Playgroud)
在dbfiddle测试。
以上是做什么的:
当为 null 或不同于 1时,CASE
表达式变为。我们可以这样写,好像这会使它更清楚。NULL
booking_status
(CASE WHEN booking_status = 1 THEN TRUE END)
(booking_status = 1 OR NULL)
唯一和排除约束接受一个或多个表达式为 NULL 的行。所以它作为一个过滤索引WHERE booking_status = 1
。
所有的WITH
操作符都是=
这样作为UNIQUE
约束的。
这两个组合使约束充当过滤的唯一索引。
但这是一个约束,EXCLUDE
可以推迟约束。
上述方法的改进(感谢Denis Ryzhkov)是使用部分(过滤的)EXCLUDE 约束。使用更少的空间(与部分索引相同)并且是可延迟的:
ALTER TABLE booking
ADD CONSTRAINT unique_booking
EXCLUDE
( check_in WITH =,
check_out WITH =
)
WHERE (booking_status = 1)
DEFERRABLE INITIALLY DEFERRED ;
Run Code Online (Sandbox Code Playgroud)
在dbfiddle-2测试。
归档时间: |
|
查看次数: |
8840 次 |
最近记录: |