通过 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
表中的检查将约束应用于 users
表和groups
表中的列。同样,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 版本。