PostgreSQL - 多重约束

PostgreSQL - Multiple constraints

我想添加几个 CHECK CONSTRAINTS 到 PostgreSQL 13 table。在自然语言逻辑中是:如果一个字段包含定义的值,则必须填充另一个字段。我有几个场景可以结合起来。当我只添加一个约束时没问题,但是当我想累积它们时,CONSTRAINTS 不受尊重并且无法插入行。

这是我的 table:

CREATE TABLE IF NOT EXISTS demo_table
(
    uuid uuid NOT NULL DEFAULT uuid_generate_v4(),
    id integer NOT NULL DEFAULT nextval('demo_table_id_seq'::regclass),        
    thematic character varying COLLATE pg_catalog."default",        
    field_a character varying COLLATE pg_catalog."default",        
    field_b character varying COLLATE pg_catalog."default",        
    CONSTRAINT demo_table_pkey PRIMARY KEY (uuid),
    CONSTRAINT field_a_check CHECK (thematic::text ~~ 'A'::text AND field_a IS NOT NULL),
    CONSTRAINT field_b_check CHECK (thematic::text ~~ 'B'::text AND field_b IS NOT NULL)
)

我预期的逻辑是:当 thematic 像 'A' 时,field_a 不能是 NULL 或者当 thematic 像 'B' field_b 不能是 NULL。使用此设置我无法添加行,因为我的 CONSTRAINTS 定义从不检查这两个条件 (field_a IS NOT NULL and field_b IS NOT NULL).

我试图按照此 中的建议定义一个唯一的 CONSTRAINT,但 CHECK CONSTRAINT 也不受尊重,因为隔离条件的括号未保存在定义中。

CREATE TABLE IF NOT EXISTS demo_table
(
    uuid uuid NOT NULL DEFAULT uuid_generate_v4(),
    id integer NOT NULL DEFAULT nextval('demo_table_id_seq'::regclass),        
    thematic character varying COLLATE pg_catalog."default",        
    field_a character varying COLLATE pg_catalog."default",        
    field_b character varying COLLATE pg_catalog."default",        
    CONSTRAINT demo_table_pkey PRIMARY KEY (uuid),
    CONSTRAINT field_a_b_check CHECK (thematic::text ~~ 'A'::text AND field_a IS NOT NULL OR thematic::text ~~ 'B'::text AND field_b IS NOT NULL)
)

如何组合多个 CONSTRAINTS 比如 (IF ... ) OR (IF ... ) OR (IF ...)

你的方法的问题是你的约束不完整。 例如:

CONSTRAINT field_a_check CHECK (thematic::text ~~ 'A'::text AND field_a IS NOT NULL),

约束表示“如果 thematic 包含 'A' 且 field_a 不为空,则记录正常”。这意味着记录不正确(如果它不包含 'A')。如果您在支票上附加了“否则还可以”,那么您可能会有几个 - 没问题:

CONSTRAINT field_a_check CHECK (thematic::text ~~ 'A'::text AND field_a IS NOT NULL OR NOT thematic::text ~~ 'A'::text)

至于为什么删除括号 - 这是因为不需要它们。 AND 运算符优先于 OR,所以表达式有无括号都是一样的。

欢迎您在db<>fiddle

查看解决方案

你可以这样做。

alter table table_1 
add constraint ck_only_one check ((col1 is null and col2 is not null) or (col2 is null and col1 is not null)); 

为了更好地隔离,要用括号分隔。