Belayer and Bergi beat me to posting the partial unique approach, so for sports: you can make an exclusion constraint work for this. demo
create type status_enum as enum('pending','in_process','completed','declined');
create table orders (
id smallserial primary key,
user_id int,
status status_enum default 'pending',
exclude (user_id with =) where (status in ('pending','in_process') )
);
insert into orders (status,user_id) values
('completed', 1),
('in_process',1),
('pending', 2);
--INSERT 0 3
insert into orders (user_id,status) values (1,'pending');
--ERROR: conflicting key value violates exclusion constraint "orders_user_id_excl"
--DETAIL: Key (user_id)=(1) conflicts with existing key (user_id)=(1).
insert into orders (user_id,status) values (1,'in_process');
--ERROR: conflicting key value violates exclusion constraint "orders_user_id_excl"
--DETAIL: Key (user_id)=(1) conflicts with existing key (user_id)=(1).
insert into orders (user_id,status) values (1,'declined');--no problem
--INSERT 0 1
Among those where status in ('pending','in_process')
, no two user_id
's can be the same.
I said this is for sports because it can work, but offers no benefits over the partial unique:
Although it's allowed, there is little point in using B-tree or hash indexes with an exclusion constraint, because this does nothing that an ordinary unique constraint doesn't do better.