数据库设计中存在冲突的欲望,具有两个相似功能的字段
-
02-07-2019 - |
题
好的,我正在为“Box Items”制作一张桌子。
现在,一个Box Item,取决于它用于什么/项目的状态,可能最终与“Shipping”相关联。框或“返回”框框。
Box Item可能有缺陷:如果是,则在Box Item的行(IsDefective)中设置一个标志,Box Item将被置于“返回”状态。框(其他项目将返回给该供应商)。否则,Box Item最终将被放入“Shipping”中。包装盒(包含其他物品)。 (请注意,Shipping和Returns框有自己的表:所有框都没有一个公共表格......虽然如果可能的话,我应该考虑这样做,作为第三种可能性?)
也许我今天没有想清楚,但我开始质疑在这种情况下应该做些什么。
我的直觉告诉我,对于每个可能的关系,我应该有一个单独的字段,即使在任何给定时间只能发生其中一个关系,这会使Box Items的架构看起来像:
BoxItemID 描述 IsDefective ShippingBoxID ReturnBoxID 等...
这会使关系变得清晰,但似乎很浪费(因为任何时候只会使用其中一种关系)。那么我想我可以只为BoxID创建一个字段,并根据IsDefective字段确定它所引用的BoxID(一个Shipping或一个返回Box ID):
BoxItemID 描述 IsDefective BoxID 等...
这似乎不那么浪费,但并不适合我。这种关系并不明显。
所以,我把它给你,Stackoverflow的数据库大师。在这种情况下你会做什么?
编辑:谢谢大家的意见!给了我很多思考的东西。首先,我将在下次启动这样的项目时使用ORM。 =)对于两个,因为我现在不对,我会咬四个字节并使用两个字段。再次感谢大家!
解决方案
我患有精神病毒和哑膜。
走多态路径(必须根据另一个字段的内容找出你的外键指向哪个表)将是一个痛苦。编写那些约束可能很难(我不确定大多数数据库会支持本机,我认为你必须使用触发器)。
物品是否会在桌子之间移动?坚持使用两个具有相同定义的表,其中一个用于返回,一个用于运输可能是最简单的路径。如果你想坚持你最初提出的定义(使用两个单独的字段)是完全合理的。
“过早优化是所有邪恶的根源”所有这一切。虽然看起来很浪费,但请记住你要存放的东西。由于它们是ID,它们可能只是整数,可能是4个字节。每条记录浪费四个字节基本上没什么。实际上,由于填充物以便将物品放在偶数地址或其他类似物上,因此它可以是“自由的”。把那个额外的字段放在那里。这完全取决于数据库设计。
除非你有充分的理由去采用多态路径(就像你在一个内存很少的嵌入式系统上,或者你必须在一些非常慢的9600bps链路上复制),否则你可能不值得头疼。以结束。必须将所有这些特殊情况写入您的查询可能会很烦人。
快速示例:在两个表之间进行连接,如果要连接,则基于是否设置了isDefective标志会很麻烦。仅仅使用两列中的一列可能足以让你节省下来的麻烦,至少对我而言。
其他提示
我会考虑为盒子制作一个表格,而盒子类型是盒子表格的一列。这将简化关系并使查询框类型变得容易。所以盒子项只有一个外键到boxId。
我会使用Hibernate所谓的表 - 每个子类,所以我的数据库最终会有3个表格用于Boxes: Box
, ShippingBox
和 ReturnBox
。 BoxItem
中的FK将指向 Box
。
你所谈论的是多态关系。可以引用多个其他表的单个ID。有几个框架支持这一点,但是,它(可能)不利于数据库完整性(可能是一个完整的其他讨论,无论您的数据库或您的应用程序是否应保持参照完整性)。
这个怎么样?
BoxItem:
BoxItemID, Description, IsDefective
Box:
BoxID, Description
BoxItemMap:
BoxID, BoxItemID, BoxItemType
然后你可以将BoxItemType作为枚举,或者在你的应用程序中将常量定义为“返回”的整数。或“运输”作为盒子的类型。
同意上面的多态性讨论,虽然它有可能被用得很差,但它仍然是一个可行的解决方案。
基本上你有一个名为box的基表。然后你有另外两个表,包装箱和退货箱。这两个添加任何特殊的额外字段。它们与1:1 fk.Boz基表的框相关,具有所有框类型的公共字段。
您将BoxItem与框表相关联。获得正确的框类型的方法是通过执行查询,根据键将子框与根框连接。基本框和子框中的记录都属于该类型。
你必须要小心提到,当你创建一个正确完成的盒子类型时。这就是测试的目的。添加它们的代码只需要写一次。或使用ORM。
几乎所有ORM都支持这一策略。
我只使用一个包含IsDefective,ShippingBoxID,发货箱相关字段,ReturnBoxID和返回框相关字段的BoxItems表。每条记录的某些字段始终为NULL。
这是一个非常简单和不言而喻的设计,下一个开发人员不太可能会被混淆。从理论上讲,这种设计效率很低,因为每行都有保证的空场。实际上,无论如何,数据库往往具有每行所需的最小存储大小,因此(除非字段数量很大),这种设计尽可能高效,并且更容易编码。
我可能会选择:
BoxTable:
box_id, box_descrip, box_status_id ...
1, Lovely Box, 1
2, Borked box, 2
3, Ugly Box, 3
4, Flammable Box, 4
BoxStatus:
box_status_id, box_status_name, box_type_id, ....
1,Shippable, 1
2,Return, 2
3,Ugly, 2
4,Dangerous,3
BoxType:
box_type_id, box_type_name, ...
1, Shipping box, ...
2, Return box, ....
3, Hazmat box, ...
通过这种方式,Box Status定义了框类型,如果您需要稍后扩展到更多状态级别或框类型,它将非常灵活。