我在Postgres中有一个表,其中包含 Things 。这些事物中的每一种都可以是3种类型之一:
本质上,从对象的角度来说,有一个AbstractThing,扩展为 SuperThingA或SuperThingB的不同方式以及所有记录 Thing表在2个中的1个中未扩展或扩展 方式。
为了在Thing表上表示这一点,我具有许多所有类型的Things共有的字段,并且在SuperThingA和SuperThingB表中有2个可选的FK参考列。
理想情况下,我希望对两者分别使用“ FK IF NOT NULL”约束,但这似乎是不可能的。据我所知,我所能做的就是使两个字段都可为空,并依靠使用代码来维护FK关系,这很麻烦。根据{{3}},这似乎在其他数据库(例如SQL Server)中是可行的,但到目前为止,我在PG中找不到的任何方式
我还能如何处理-插入/更新触发器,当这些字段中的任何一个都不为null时检查该值并检查在任何父表中是否存在该值?这对于在Thing表上插入有限的小型父表可能是可行的(公平地说,在这里主要是这种情况-每个父表中最多只有几百条记录,而Thing上的插入量很少表),但在更一般的情况下,如果一个或两个父表都很大,则会在插入时出现性能黑洞
当前未通过FK关系强制实施。我已经查看了PG文档,并且似乎可以确定我没有可选的FK关系(这是可以理解的)。它给我留下了一个类似这样的表定义:
CREATE TABLE IF NOT EXISTS Thing(
Thing_id int4 NOT NULL,
Thing_description varchar(40),
Thing_SuperA_FK int4,
Thing_SuperB_FK char(10),
CONSTRAINT ThingPK PRIMARY KEY (Thing_id)
)
;
答案 0 :(得分:1)
可空列上的每个外键仅在值非空时强制执行。这是默认行为。
create table a (
id int4 not null primary key
);
create table b (
id int4 not null primary key,
a_id int4 references a(id)
);
在示例中,表b具有对表a的可选引用。
insert into a values(1); -- entry in table a
insert into b values (1, 1); -- entry in b with reference to a
insert into b values (2, null); -- entry in b with no reference to a
根据您的用例,反转表结构也很有意义。与其让公用表指向另外两个专用表,不如让它反过来。这样,您可以完全避免使用非null列。
create table common(
id int4 primary key
-- all the common fields
);
create table special1(
common_id int4 not null references common(id)
-- all the special fields of type special1
);
create table special2(
common_id int4 not null references common(id)
-- all the special fields of type special2
);
答案 1 :(得分:0)
您需要将SuperN_FK
字段定义为可为空的外键,然后您需要在表上使用检查约束来强制执行可选的NULLability要求。
CREATE TABLE Things
( ID int primary key
, col1 varchar(1)
, col2 varchar(1)
, SuperA_FK int constraint fk_SuperA references Things(ID)
, cola1 varchar(1)
, constraint is_SuperA check ((SuperA_FK is null and cola1 is null) or
(SuperA_FK is not null and cola1 is not null))
, SuperB_FK int constraint fk_SuperB references Things(ID)
, colb1 varchar(1)
, constraint is_SuberB check ((SuperB_FK is null and colb1 is null) or
(SuperB_FK is not null))
, constraint Super_Constraint check (
case when SuperA_FK is not null then 1 else 0 end +
case when SuperB_FK is not null then 1 else 0 end
<= 1 )
);
在上面的示例中,我将检查约束进行了拆分,以简化维护。这两个is_SuperN约束对FK及其相关的明细列强制执行NULL要求,要么全部为NULL,要么FK不为空,并且某些或所有明细列都不为空。最后的Super_Constraint确保最多一个SuperN_FK不为null。