为了账号安全,请及时绑定邮箱和手机立即绑定

如何创建多个一对一的

/ 猿问

如何创建多个一对一的

慕仰8121524 2019-08-19 16:58:39

如何创建多个一对一的

我有一个设置了许多表的数据库,除了一点之外它看起来都很好......

Inventory Table <*-----1> Storage Table <1-----1> Van Table
                              ^
                              1
                              |-------1> Warehouse Table

由于Van和Warehouse表相似,因此使用了Storage表,但如何在Storage和Warehouse / Van表之间创建关系?因为存储对象只能是1个存储位置和类型,所以它们需要为1比1。我确实有Van / Warehouse表链接到StorageId主键,然后添加一个约束,以确保Van和Warehouse表没有相同的StorageId,但这似乎可以做得更好。

我可以看到这样做的几种方法,但它们都显得不对,所以任何帮助都会很好!


查看完整描述

3 回答

?
皈依舞

您正在使用继承(在实体关系建模中也称为“子类”或“类别”)。通常,有3种方法可以在数据库中表示它:

  1. “一个表中的所有类”:只有一个表“覆盖”父类和所有子类(即包含所有父列和子列),具有CHECK约束以确保正确的字段子集非NULL(即两个不同的孩子们不“混”)。

  2. “每个表的具体类”:为每个子项创建一个不同的表,但没有父表。这需要在所有孩子中重复父母的关系(在您的情况下,库存< - 存储)。

  3. “每个表的类”:为每个孩子设置一个父表和一个单独的表,这是你要做的。这是最干净的,但可能会花费一些性能(主要是在修改数据时,而不是在查询时,因为您可以直接从子级加入并跳过父级)。

我通常更喜欢第三种方法,但在应用程序级别强制执行子项的存在排他性。在数据库级别执行这两者有点麻烦,但如果DBMS支持延迟约束,则可以完成。例如:

CHECK (
    (
        (VAN_ID IS NOT NULL AND VAN_ID = STORAGE_ID)
        AND WAREHOUSE_ID IS NULL
    )
    OR (
        VAN_ID IS NULL
        AND (WAREHOUSE_ID IS NOT NULL AND WAREHOUSE_ID = STORAGE_ID)
    ))

这将强制执行孩子的排他性(由于CHECK)和存在(由于CHECKFK1/ 的组合FK2)。

遗憾的是,MS SQL Server 不支持延迟约束,但您可以“隐藏”存储过程背后的整个操作,并禁止客户端直接修改表。


只有排他性可以在没有延迟约束的情况下强制执行:


STORAGE_TYPE是一个类型鉴别器,通常是一个节省空间的整数(在上面的例子中,0和1对应用程序是“已知的”并相应地进行解释)。

VAN.STORAGE_TYPEWAREHOUSE.STORAGE_TYPE可以计算(又名“计算”)的列,以节省存储和避免对需要CHECK秒。

---编辑---

计算列可以在SQL Server下工作,如下所示:

CREATE TABLE STORAGE (
    STORAGE_ID int PRIMARY KEY,
    STORAGE_TYPE tinyint NOT NULL,
    UNIQUE (STORAGE_ID, STORAGE_TYPE));CREATE TABLE VAN (
    STORAGE_ID int PRIMARY KEY,
    STORAGE_TYPE AS CAST(0 as tinyint) PERSISTED,
    FOREIGN KEY (STORAGE_ID, STORAGE_TYPE) REFERENCES STORAGE(STORAGE_ID, STORAGE_TYPE));CREATE TABLE WAREHOUSE (
    STORAGE_ID int PRIMARY KEY,
    STORAGE_TYPE AS CAST(1 as tinyint) PERSISTED,
    FOREIGN KEY (STORAGE_ID, STORAGE_TYPE) REFERENCES STORAGE(STORAGE_ID, STORAGE_TYPE));-- We can make a new van.INSERT INTO STORAGE VALUES (100, 0);INSERT INTO VAN VALUES (100);-- But we cannot make it a warehouse too.INSERT INTO WAREHOUSE VALUES (100);-- Msg 547, Level 16, State 0, Line 24-- The INSERT statement conflicted with the FOREIGN KEY constraint "FK__WAREHOUSE__695C9DA1". The conflict occurred in database "master", table "dbo.STORAGE".

不幸的是,SQL Server要求在外键中使用的计算列为PERSISTED。其他数据库可能没有此限制(例如Oracle的虚拟列),这可以节省一些存储空间。


查看完整回答
反对 回复 2019-08-19
?
慕少森

如你所说,有很多解决方案。我建议从最简单的解决方案开始,然后在性能或存储成为问题时进行优化。最简单的解决方案(但在存储方面不是最佳的)是使存储表具有存储类型的列(指示行是代表货车还是仓库),还有Van属性列和Warehouse属性。在表示Van的行中,Warehouse属性的列都将为null。在表示Warehouse的行中,Van属性的列都将为null。

这样,您减少了表的数量,并使您的查询保持简洁。如果存储变得紧张,请准备好重新审视您的决定。


查看完整回答
反对 回复 2019-08-19
?
慕婉清6462132

在某种程度上,在我看来,库存物品可能会改变位置,所以我会选择这样的东西。


查看完整回答
反对 回复 2019-08-19

添加回答

回复

举报

0/150
提交
取消
意见反馈 邀请有奖 帮助中心 APP下载
官方微信