如何创build多个一对一的
我有一个数据库build立了许多表,这一切看起来不错,除了一点点…
Inventory Table <*-----1> Storage Table <1-----1> Van Table ^ 1 |-------1> Warehouse Table
由于Van和Warehouse表类似,但是如何在Storage和Warehouse / Van表之间创build关系? 这是有道理的,他们需要是1到1,因为存储对象只能是1个存储位置和types。 我有Van / Warehouse表链接到StorageId主键,然后添加一个约束,以确保范和仓库表不具有相同的StorageId,但这似乎可以做一个更好的方法。
我可以看到这样做的几种方法,但他们都似乎错了,所以任何帮助将是好的!
您正在使用inheritance(在实体关系build模中也称为“子类”或“类别”)。 一般来说,数据库中有3种表示方法:
- “一个表中的所有类”:只有一个表“覆盖”父类和所有子类(即所有的父类和子类),使用CHECK约束来确保正确的字段子集是非NULL(即两个不同的孩子不要“混”)。
- “每个具体类”:为每个孩子有一个不同的表,但没有父表。 这要求家长的关系(在您的情况下,库存< – 存储)在所有的孩子重复。
- “每张桌子的类别”:为每个孩子设置一个父桌子和一张单独的桌子,这就是你正在做的事情。 这是最干净的,但可能会花费一些性能(主要是在修改数据时,而不是在查询时太多,因为您可以直接从子级join并跳过父级)。
我通常更喜欢第三种方法,但是在应用程序层面强化孩子的存在和排他性 。 在数据库级别执行这两个操作有点麻烦,但是如果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
)和儿童的存在(由于CHECK
和FK1
/ FK2
的组合)。
不幸的是,MS SQL Server 不支持延迟约束 ,但是你可能能够隐藏存储过程后面的整个操作,并禁止客户端直接修改表。
只要排他性可以执行没有延迟约束:
STORAGE_TYPE
是一个types鉴别器,通常是一个整数来节省空间(在上面的例子中,0和1是“已知”给你的应用程序,并相应地解释)。
可以计算VAN.STORAGE_TYPE
和WAREHOUSE.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的虚拟列),这可以节省一些存储空间。
正如你所说,有很多解决scheme。 我会build议从最简单的解决scheme开始,然后在性能或存储成为问题时进行优化。 最简单的解决scheme(但在存储方面不是最佳的)将是拥有一个存储表,其中包含一个存储types的列(指示该行是否表示货车或仓库),以及Van属性的列以及Warehouse属性。 在表示Van的行中,Warehouse属性的列将全部为空。 在表示仓库的行中,Van属性的列将全部为空。
这样,你减less了表的数量,并保持你的查询很好,很简单。 如果存储变得紧张,准备好重新考虑你的决定。
不知何故,在我看来,库存项目可能会改变地点,所以我会去这样的事情。