如何在“菱形”关系系统中保持外键关系一致

Posted

技术标签:

【中文标题】如何在“菱形”关系系统中保持外键关系一致【英文标题】:How to keep foreign key relations consistent in a "diamond-shaped" system of relationships 【发布时间】:2012-08-30 14:16:01 【问题描述】:

考虑这种情况:汽车是从销售人员处购买的。一名销售人员在陈列室(并且仅在一个陈列室)工作。陈列室隶属于制造商,仅销售该制造商制造的汽车。同时,汽车是特定的Model,而Model是由制造商制造的。

限制 R:汽车模型的制造商必须与汽车销售员的陈列室的附属制造商是同一制造商。

该图显示了明显的外键关系。

     ---->  Manufacturer  <----
     |                        |
     |                        |
 Showroom                     |
     ^                        |
     |                      Model
     |                        ^
Salesperson                   |
     ^                        |
     |                        |
     ---------  Car  ----------

您如何执行限制 R?您可以添加外键关系Car --&gt; Manufacturer。然而,汽车制造商可以通过围绕“钻石”以一种或另一种方式连接表格来建立,所以这样做肯定不会被规范化吗?但我不知道如何强制执行约束。

【问题讨论】:

这可能只是一个例子——但在这里我不会限制这一点,因为陈列室与制造商相关联,那么在那里出售的所有汽车都必须由该制造商制造......进一步- 同一销售人员可能在多个陈列室工作。 ^^ 陈列室跟厂家有什么关系? 我已经澄清了这个问题。陈列室只销售其所属制造商生产的汽车。 我会在触发逻辑中强制执行此操作。 好吧,我只能重复我的请求,请您进一步解释。哪条信息是多余的?如果我有一辆汽车,那么我需要知道它是哪种型号,并且我需要知道是谁卖的。如果我有一个模型,我需要知道是谁制造的(即使还没有该模型的任何汽车,我也需要知道这一点)。如果我有销售人员,我需要知道他们在哪里工作,并且我需要知道工作场所隶属于哪个制造商(即使它还没有销售任何汽车)。 【参考方案1】:

确保钻石的“底部”不能引用最终导致钻石的不同“顶部”的钻石“侧面”的方法是使用识别关系和生成的“胖”自然键,因此它们可以在底部合并

(为简洁起见,仅显示 PK 字段。您几乎肯定会希望将车辆识别号作为 Car 等中的备用键...)

ManufacturerId 已向下迁移到菱形两侧,并最终在底部合并为一个字段。它是单一字段的事实确保不会有两个制造商生产同一辆车。

顺便说一句,这仍然不会阻止您使用代理键(除了这些自然键),假设 DBMS 支持 FK 来替代键:

代理在这个模型中是多余的,但是你可能有一些你没有向我们展示的其他实体,这可能会从使用更纤细的 FK 中受益。


以上是您的图表的最直接转换,其中汽车仅作为已售汽车存在。但是,我怀疑您希望能够存储尚未售出的汽车,并且当它们售出时记住购车者等...

所以,一个更完整的模型应该是这样的:

我们只是反复重复识别关系技巧,因此汽车不能在不同制造商的陈列室中展示,也不能由不同陈列室的销售人员出售。

Car 中只有一行时,汽车未售出。当Car 中有一行并且Sale 中有相应行时,汽车即被售出。 CarSale 共享相同的 PK,这是“1 到 0..1”的关系,也可以通过合并 CarSale 来建模,并使 sale 的字段可以为 NULL,适当的 CHECK 以确保它们不能“部分为 NULL”。

顺便说一句,无论何时销售商品,您都需要确保销售“及时冻结”。例如,买家实际支付的价格不应该仅仅因为汽车的价格在出售后发生变化。查看here 了解更多信息。

【讨论】:

【参考方案2】:

如果我正确理解了这个问题,这应该很接近。

这里有一些键的细节

--
-- Keys for SalesPerson
--
alter table SalesPerson
  add constraint PK_salesperson primary key (PersonID)

, add constraint AK1_salesperson unique (ManufacturerID, ShowRoomNo, PersonID) 

, add constraint FK1_salesperson foreign key (PersonID)
                           references Person (PersonID)

, add constraint FK2_salesperson foreign key (ManufacturerID, ShowRoomNo)
                         references ShowRoom (ManufacturerID, ShowRoomNo)
;

--
-- keys for Sale table
--
alter table Sale
  add constraint PK_sale primary key (SaleID)

, add constraint FK1_sale foreign key (BuyerID)
                    references Person (PersonID)

, add constraint FK2_sale foreign key (ManufacturerID, ModelName, ShowRoomNo)
                references CarDisplay (ManufacturerID, ModelName, ShowRoomNo)

, add constraint FK3_sale foreign key (ManufacturerID, ShowRoomNo, SalesPersonID)
               references SalesPerson (ManufacturerID, ShowRoomNo, PersonID)
;

【讨论】:

感谢您的回答。关键的观察似乎是交叉引用表 CarDisplay 的创建,以及外键关系的更改以适应它。 @Hammerite,还要注意 SalesPerson 上的备用键(唯一索引)AKSale 表中的 FK 指向该键。

以上是关于如何在“菱形”关系系统中保持外键关系一致的主要内容,如果未能解决你的问题,请参考以下文章

如何组合 Access 2010 数据库并保持关系

数据库专业人士“采访”整理记录

如何画类图 怎样把空心菱形变成实心菱形

Spring Boot:与@JoinColumn 的 ManyToOne 关系保持外键为空

Hibernate的一对一关联关系

Laravel:当我的外键在数组中时,如何在模型中添加关系?