Postgresql多个表具有相同的外键唯一约束

Posted

技术标签:

【中文标题】Postgresql多个表具有相同的外键唯一约束【英文标题】:Postgresql multiple tables with same foreign key unique constraint 【发布时间】:2015-03-19 17:04:33 【问题描述】:

我在 PostgreSQL 9.4 上有以下表格

CREATE TABLE "user" (
    id SERIAL PRIMARY KEY,
    email CHARACTER VARYING NOT NULL,
    password CHARACTER VARYING NOT NULL
);

CREATE TABLE "dealer" (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES "user" (id) ON DELETE RESTRICT
);

CREATE TABLE "affiliate" (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES "user" (id) ON DELETE RESTRICT
);

是否可以强制 user_id 值在表 dealeraffiliate 之间是唯一的?

【问题讨论】:

您是否在询问是否可以强制执行一个约束,允许 user_id 属于经销商或附属公司,但不能同时属于两者? @PeterHeadland 是的,从本质上讲,用户可以是经销商或附属公司,不能同时是两者。 看到您的(现已删除)评论并决定扩展我的答案。 【参考方案1】:

有不同的设置用于 SQL 中的继承,为此您可以在表 user 中使用整数列 type 来标记用户的类型,并引用表 user_type (id,name) 1,dealer2,affiliate 的值:

CREATE TABLE user_type (
  id INTEGER PRIMARY KEY, --could be SERIAL
  name text
);
INSERT INTO user_type VALUES (1,'dealer'), (2, 'affiliate');

CREATE TABLE "user" (
    id SERIAL PRIMARY KEY,
    email CHARACTER VARYING NOT NULL,
    password CHARACTER VARYING NOT NULL,
    user_type INTEGER REFERENCES user_type NOT NULL,
    UNIQUE(id,user_type)
);

这本身不会强制跨表的唯一性,因此在实施后您将拥有以下选项:

删除表 dealeraffiliate - 如果您依靠类型字段来查看用户是谁,则不需要它们。

如果您必须保留那些继承的表,您可以:

使用触发器 - 这些触发器检查唯一性并将在INSERTUPDATE 上激活

另一个(有点笨拙)的解决方案:user_type 字段添加到两个子表,如下所示:

CREATE TABLE "dealer" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
user_type INTEGER NOT NULL  DEFAULT 1 check (user_type = 1),
FOREIGN KEY (user_id,user_type) REFERENCES "user"(id,user_type) ON DELETE RESTRICT
);

CREATE TABLE "affiliate" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
user_type INTEGER NOT NULL  DEFAULT 2 check (user_type = 2),
FOREIGN KEY (user_id,user_type) REFERENCES "user"(id,user_type) ON DELETE RESTRICT
);

检查和外键一起确保您不能在主表中同时拥有这两种类型的用户。请注意,user_id 也可以用作子表中的PRIMARY KEY。目前user 中的一行可能有多个链接到它的dealer 行,因此至少您可能希望将子表中的user_id 外键设置为UNIQUE

【讨论】:

以上是关于Postgresql多个表具有相同的外键唯一约束的主要内容,如果未能解决你的问题,请参考以下文章

如果我的外键已经是唯一约束的一部分,我应该索引它们吗?

外键为啥必须是唯一键?为啥至少唯一键才能作为其他表的外键?不唯一为啥不可以?

在 PostgreSQL Flask 中删除具有外键的行

单个查询中的 Postgresql 多个连接,其中连接的外键不存在于所有表中

PostgreSQL中复合类型列子列的外键约束

从表 2 中的外键约束中删除表 1 中确实具有主键的记录