对不能同时为空的多列的唯一约束

Unique constraints on multiple columns that cannot both be null

我想问一下在 Postgres 10 中是否有更好的建模以下行为的方法:

CREATE TABLE test.my_table
(
    id   UUID PRIMARY KEY,
    id_a UUID,
    id_b UUID,
    some_shared_data JSONB,
    UNIQUE (id_a, id_b)
);

CREATE UNIQUE INDEX IF NOT EXISTS b_null_constraint ON test.my_table (id_a) WHERE id_b IS NULL;
CREATE UNIQUE INDEX IF NOT EXISTS a_null_constraint ON test.my_table (id_b) WHERE id_a IS NULL;

ALTER TABLE test.my_table
    ADD CONSTRAINT both_null_constraint CHECK (
        (id_b IS NOT NULL) OR (id_a IS NOT NULL));

即约束是:

  1. id_aid_b都不能是null
  2. id_aid_b 的组合必须是唯一的(包括其中之一是 null 的情况)

感觉上面设置这个的代码表达能力不是很好。人们会以 another/more 规范化的方式这样做吗?我试着把它分成不同的表,但约束 (1.) 很难满足。

只需两个 unique 约束就可以做到这一点。第二个是:

CREATE UNIQUE INDEX IF NOT EXISTS ab_null_constraint ON my_table ( coalesce(id_a, id_b), (id_a is null) WHERE id_a IS NULL or id_b is null;

Here 是一个 db<>fiddle.

实际上,您可以将所有这些组合成一个唯一索引:

CREATE UNIQUE INDEX IF NOT EXISTS ab_null_constraint ON
     my_table ( coalesce(id_a, id_b),
                coalesce(id_b, id_a),
                (id_a is null),
                (id_b is null)
              );

Here 是一个 db<>fiddle。

您可能会发现您的原始公式更易于维护。