Postgres 对插入/更新的排除约束

问题描述

我有一个这样定义的表

                               Table "public.foo"
  Column  |  Type   | Collation | Nullable |               Default               
----------+---------+-----------+----------+-------------------------------------
 foo_id   | integer |           | not null | nextval('foo_foo_id_seq'::regclass)
 bar_id   | integer |           |          | 
 approved | boolean |           |          | 
Indexes:
    "foo_pkey" PRIMARY KEY,btree (foo_id)
Foreign-key constraints:
    "foo_bar_id_fkey" FOREIGN KEY (bar_id) REFERENCES bar(bar_id)

我将如何定义排除约束,以便只有一行具有特定 foobar_id 能够将 approved 设置为 true?

例如以下数据:

 foo_id | bar_id | approved 
--------+--------+----------
      1 |      1 | t
      2 |      1 | 
      3 |      2 | 
(3 rows)

我可以将 approved 的第 3 行设置为 true,因为没有其他具有 foo_id 3 的行被批准为 true。

然而,将第 2 行的 approved 更新为 true 会失败,因为第 1 行也有 foo_id 1 并且已经被批准。

解决方法

您不需要排除约束,过滤的唯一索引就可以:

create unique index only_one_approved_bar 
   on foo (bar_id)
   where approved;

我还建议将 approved 定义为 not null。允许 null 值的布尔列通常是不断混淆的根源。

,

试试这个

ALTER TABLE public.foo
ADD CONSTRAINT uniq_approved UNIQUE (bar_id,approved)

或者你可以创建唯一索引

CREATE UNIQUE INDEX uniq_approved ON public.foo
USING btree (bar_id,approved)
WHERE approved