加强约束“两张桌子”


10

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

  part ←────────── pin
                   
part_inst ←───── pin_inst

其中“实例”是“实例”的缩写。

例如,作为partLM358运算放大器,我可能具有pins 1OUT,1IN-,1IN +,GND,2IN +,2IN-,2OUT和V CC。然后,我可能将此零件放在原理图上,并创建一个part_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
);

这种模式的主要问题是a pin_inst可能part_inst与with 绑定在一起,part_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              --
);

我对这种方法的抱怨是,它污染了主键:在我所指的a处part_inst,我都需要同时跟踪the part_inst_id和the part_id。我还有另一种方法可以执行约束 pin_inst.part_inst.part_id = pin_inst.pin.part_id而又不会过于冗长吗?


您也可以删除pin_inst_id多余的。您可以使用(part_inst_id, part_id, pin_id)as作为主键。
ypercubeᵀᴹ

两件事:(a)1OUT,1IN-,1IN +,GND,2IN +,2IN-,2OUT和VCC不会产生11个引脚实例吗?(b)我没有得到您的初始架构。不能将销钉用于多个部分吗?您需要引脚和零件之间的NN关系,而不是1-N。
Marcus Junius Brutus 2014年

@ user34332:(a)数字是名称的一部分。例如,“ 2OUT”是单个引脚。这是我正在讨论的芯片示意图。(b)我不同意。当然,两个部分可能具有VCC(正电源电压,“公共集电极电压”)引脚,但是在逻辑上它们是不同的引脚。例如,一个VCC引脚通常可以汲取500 µA,而另一个则可以汲取250 µA。
雪球2014年

@Snowball如果您添加带有示例数据的SQL-Fiddle,它将帮助其他人理解您的架构。
ypercubeᵀᴹ

Answers:


13

最小的解决方案

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

  part ←────────── pin
                   
part_inst ←───── pin_inst

您的问题中没有任何内容表明您实际上需要冗余表。对于pin与关联的part_inst,请查看pin关联的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
);

但是您的评论清楚地表明,我们将无法摆脱...

如果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
);

我将part_id独特的约束放在首位。这与引用完整性无关,但对性能很重要。主键已经实现了pk列的索引。最好是有其他的第一列执行唯一约束的多列索引。这些相关问题下的详细信息:

有关SO的相关问题:

触发器替代

您可以使用触发器函数,该函数更灵活,但更复杂,更容易出错且不太严格。好处:你可以没有part_inst.part_idpin.part_id...


中还有其他一些列pin_insts,但是出于可读性考虑,我省略了它们(“忽略数据字段,[...]”)。例如,pin_inst可以将a标记为输入或输出。
Snowball

@Snowball:本来很容易做到。我扩大了您的解决方案。
Erwin Brandstetter

2
您的第二个建议适合我的情况。我不知道外键可以引用主键以外的其他内容。
雪球2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.