在 Postgres 中跨表应用的非唯一约束名称

时间:2021-03-09 20:15:10

标签: postgresql constraints

通过 SQLAlchemy 和 Alembic,我创建了一些共享名称但在其他方面相互独立的表约束。这会产生一些令人惊讶的结果,其中约束检查应用于与约束规范不匹配的表中的列。

可重现的例子:

DROP TABLE IF EXISTS users;

CREATE TABLE users (
    id UUID DEFAULT uuid_generate_v4() NOT NULL,
    created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
    updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
    join_date DATE,
    userrole VARCHAR(19) NOT NULL,
    status VARCHAR(24) NOT NULL,
    PRIMARY KEY (id),
    CONSTRAINT role CHECK (userrole IN ('standard', 'admin', 'readonly'))
);

DROP TABLE IF EXISTS groups;

CREATE TABLE groups (
    id UUID DEFAULT uuid_generate_v4() NOT NULL,
    grouprole VARCHAR(19) NOT NULL,
    created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
    updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
    status VARCHAR(24) NOT NULL,
    PRIMARY KEY (id),
    CONSTRAINT role CHECK (grouprole IN ('foo', 'bar', 'baz'))
);

users 表中的检查将约束应用于 usersgroups 表中的列。同样,groups 表中的检查将约束应用于 groups users 表中的列。

检查在表之间交叉的地方,它应用于索引处的列,您希望它应用于定义它的表中。上面的例子结果如下:

用户:

<头>
姓名 类型 可以为空 检查 默认
1 id uuid 没有 NULL uuid_generate_v4()
2 created_at 时间戳 没有 (role)::text = ANY ((ARRAY['foo'::character 变化,'bar'::character 变化,'baz'::character 变化])::text[]) NULL
3 updated_at 时间戳 没有 NULL NULL
4 加入日期 日期 NULL NULL
5 用户角色 varchar(19) 没有 (role)::text = ANY ((ARRAY['standard'::character 可变,'admin'::character 可变,'readonly'::character 可变])::text[]) NULL
6 状态 varchar(24) 没有 NULL NULL

组:

<头>
姓名 类型 可以为空 检查 默认
1 id uuid 没有 NULL uuid_generate_v4()
2 组角色 varchar(19) 没有 (role)::text = ANY ((ARRAY['foo'::character 变化,'bar'::character 变化,'baz'::character 变化])::text[]) NULL
3 created_at 时间戳 没有 NULL NULL
4 updated_at 时间戳 没有 NULL NULL
5 状态 varchar(24) 没有 (role)::text = ANY ((ARRAY['standard'::character 可变,'admin'::character 可变,'readonly'::character 可变])::text[]) NULL

更改约束之一的名称足以解决此问题。这是约束应该起作用的方式吗?

我创建了一个 DB Fiddle,显示它适用于多个 Postgres 版本。

0 个答案:

没有答案