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_inst
s。
忽略数据字段,我对模式的最初尝试是
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_inst
withpart_id=1
但它的pin
has 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_id
和part_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_inst
的pin
s ,请查看相关联的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_id
和pin.part_id
...