我有一张桌子
orders
,其中包含以下列:id
,user_id
和status
。 status
列是枚举值:pending, in_process, completed, declined.
我需要禁止用户使用
status in (pending, in_process)
拥有多个订单。
例如,有桌子:
id | 状态 | user_id |
---|---|---|
1 | 完成 | 1 |
2 | 进程中 | 1 |
3 | 待定 | 2 |
对于
pending
,我们不应该再插入一个状态为in_process
或状态为user_id=1
的订单。
我觉得我应该在这里使用排除约束,但不知道如何禁止两个集合的交集。
您正在寻找的是部分唯一索引。由于
status
是一个枚举,您很可能必须对数组进行类型转换。
create unique index on orders (user_id, status)
where status = any ( array['pending', 'in_process']::status_enum[] );
你不是在这里寻找排除约束(因为你想允许任意数量的
completed
行,这些行都具有相同的 user_id
和 status
值)而是一个 conditionally unique constraint - which postgres 不支持 CONSTRAINT
,但你可以使用 partial UNIQUE
index:
CREATE UNIQUE INDEX unique_active_order
ON orders (user_id)
WHERE (status IN ('pending', 'in_process'));
或
CREATE UNIQUE INDEX unique_active_order
ON orders (user_id)
WHERE (status <> 'completed');
Belayer 和 Bergi 比我先发布部分独特的方法,所以对于运动:你 can 做一个 exclusion constraint 工作。 演示
create table orders (
id smallserial,
user_id int,
status text check (status in ('pending','in_process','completed','declined') ),
exclude (user_id with =) where (status in ('pending','in_process'))
);
但它没有任何好处:
虽然允许,但使用具有排除约束的 B 树或哈希索引没有什么意义,因为这没有做普通唯一约束不能做得更好的事情。所以在实践中,访问方法将始终是 GiST 或 SP-GiST。