强制约束“两个表”

Sno*_*all 13 postgresql foreign-key database-design referential-integrity polymorphic-associations

我在 SQL 中对电气原理图建模时遇到了一些麻烦。我想捕获的结构是

  part ??????????? pin
   ?                ?
part_inst ?????? pin_inst
Run Code Online (Sandbox Code Playgroud)

其中“inst”是“instance”的缩写。

例如,我可能part将 LM358 运算放大器pin用作 1OUT、1IN-、1IN+、GND、2IN+、2IN-、2OUT 和 V CC。然后我可能会将这部分放在原理图上,创建 apart_inst和 8 pin_insts。

忽略数据字段,我对模式的最初尝试是

create table parts (
    part_id bigserial primary key
);
create table pins (
    pin_id bigserial primary key,
    part_id bigint not null references parts
);
create table part_insts (
    part_inst_id bigserial primary key,
    part_id bigint not null references parts
);
create table pin_insts (
    pin_inst_id bigserial primary key,
    part_inst_id bigint not null references part_insts,
    pin_id bigint not null references pins
);
Run Code Online (Sandbox Code Playgroud)

这种模式的主要问题是 apin_inst可能绑定到part_instwithpart_id=1但它的pinhas part_id=2

我想在数据库级别而不是应用程序级别避免这个问题。所以,我修改了我的主键来强制执行。我用 标记了更改的行--

create table parts (
    part_id bigserial primary key
);
create table pins (
    pin_id bigserial,                                          --
    part_id bigint not null references parts,
    primary key (pin_id, part_id)                              --
);
create table part_insts (
    part_inst_id bigserial,                                    --
    part_id bigint not null references parts,
    primary key (part_inst_id, part_id)                        --
);
create table pin_insts (
    pin_inst_id bigserial primary key,
    part_inst_id bigint not null,                              --
    pin_id bigint not null,                                    --
    part_id bigint not null references parts,                  --
    foreign key (part_inst_id, part_id) references part_insts, --
    foreign key (pin_id, part_id) references pins              --
);
Run Code Online (Sandbox Code Playgroud)

我对这种方法的抱怨是它污染了主键:在我提到的任何地方part_inst,我都需要跟踪 part_inst_idpart_id。有没有另一种方法可以pin_inst.part_inst.part_id = pin_inst.pin.part_id在不过于冗长的情况下强制执行约束 ?

Erw*_*ter 15

最小解

一种激进的解决方案可能是pin_inst完全删除:

  part ??????????? pin
    ?               ?
part_inst ?????? pin_inst
Run Code Online (Sandbox Code Playgroud)

您的问题中没有任何内容表明您实际上需要冗余表。对于pin与 a 相关联part_instpins ,请查看相关联的s part

这会将代码简化为:

create table part (    -- using singular terms for table names
    part_id bigserial primary key
);
create table pin (
    pin_id bigserial primary key,
    part_id bigint not null references part
);
create table part_inst (
    part_inst_id bigserial primary key,
    part_id bigint not null references part
);
Run Code Online (Sandbox Code Playgroud)

但是你的评论清楚地表明我们不会逃脱...

如果pin_inst需要,可以替代

part_id像您一样包括是具有外键约束的最简单的解决方案。您不能引用具有外键约束的“两个表”表。

但是您至少可以在不“污染”主键的情况下凑合。添加UNIQUE约束

create table part (
    part_id bigserial primary key
);
create table pin (
    pin_id bigserial primary key,
    part_id bigint not null references part,
    unique(part_id, pin_id)         -- note sequence of columns
);
create table part_inst (
    part_inst_id bigserial primary key,
    part_id bigint not null references part,
    unique(part_id, part_inst_id)
);
create table pin_inst (
    pin_inst_id bigserial primary key,
    part_inst_id bigint not null,
    pin_id bigint not null,
    part_id bigint not,
    foreign key (part_id, pin_id) references pin,
    foreign key (part_id, part_inst_id) references part_inst
);
Run Code Online (Sandbox Code Playgroud)

我把part_id唯一的约束放在第一位。这与参照完整性无关,但对性能很重要。主键已经为 pk 列实现了索引。最好在实现唯一约束的多列索引中首先使用另一列。这些相关问题下的详细信息:

SO的相关问题:

替代触发器

您可以求助于触发器函数,它更灵活,但更复杂、更容易出错,并且不那么严格。好处:你可以没有part_inst.part_idpin.part_id...