SQL数据库设计问题

时间:2009-08-05 03:45:03

标签: sql database-design

目前我正在努力解决数据库设计问题,我将简要介绍一下正在发生的事情:

假设我有四个表,Equipment,CurrentState,StateValue,StateType,具有以下模式:

Equipment
------------
Id (PK),
Name


CurrentState
------------
Id (PK),
EquipmentId (FK) (IX),
StateValueId (FK),
StateTypeId (FK) (IX)


StateValue
------------
Id (PK),
StateTypeId (FK),
Name


StateType
-----------
Id (PK),
Name

一件设备可以有几个属于不同 StateTypes的不同CurrentStates,因此是唯一索引(IX)。 StateType基本上是状态机,StateValue包含每个状态机的值。

现在,我的问题,即2个问题,围绕CurrentState和StateValue表中的StateTypeId外键,它们确定CurrentType记录是什么StateType以及StateValue记录是什么StateType。

首先,在参照完整性方面,这种关系设计不好吗?我的猜测是它设计不好,因为在CurrentState表和StateType表之间应该只有一个链接,这是通过StateValue,否则一个CurrentState记录可能最终有两个不同的StateTypes(一个通过直接FK和其他通过StateValue表FK)......

但是第二个问题来了:如果我不应该在CurrentState表中有一个StateTypeId FK,我该如何强制执行索引,这确保单个EquipmentId没有两个CurrentState记录,其中StateValueIds指向StateValue记录相同的StateType ......

插入CurrentState表时是否必须使用触发器来检查是否遵循规则?我之前从未使用过触发器,所以我需要做一些研究。我也在使用实体框架,并且不知道这对它有什么影响(理论上不应该有)。

4 个答案:

答案 0 :(得分:2)

是的,这是不好的做法,因为一个当前值可以有两种不同的状态类型。将StateTypeId列从CurrentState中删除,并使其仅通过StateValueId。您的唯一索引应位于CurrentStateStateValueId

当然,如果您坚持在StateTypeId中使用CurrentState,则可以设置check约束,以确保StateTypeId等于StateTypeId 1}}来自StateValueId。但这真的很迂回。将它们全部留在自己的孤岛中会更清洁,更易于维护。

答案 1 :(得分:0)

您的设计问题不在于表格中的列设计。您可以保留在建议的解决方案中提供的相同列,并从性能和灵活性角度获得更好的结果。

您需要做的是在CurrentState和StateValue之间设置复合引用约束,并删除CurrentState和StateType之间的引用约束。 (我在你的问题陈述中没有看到这个约束,但是我从你使用“FK”开始就假定它。)我忘记了复合引用约束的语法(可能是DBMS特定的),但是它类似于< / p>

CONSTRAINT ValidState FOREIGNKEY(StateValueId,StateTypeId)REFERENCES StateValue(Id,StateTypeId)

这将是CurrentState的定义。不要担心CurrentState不引用StateType这一事实。因为StateValue引用StateType,所以您的约束将一起传递。复合约束将确保您不存储状态值与当前状态中的状态类型之间的关系,该关系与存储在StateValue中的相同关系相矛盾。

现在,您可以创建一个唯一索引,将CurrentState中三个外键中的两个绑定在一起。

在CurrentState上创建UNIQUE INDEX CurrentStateIDX(EquipmentId,StateTypeId)。

如果我正在进行设计,我会完全删除列CurrentState.ID。然后,我将为CurrentState定义一个复合主键,列出EquipmentID和StateTypeID。这将导致DBMS(在大多数情况下)以最佳方式组织表以进行连接,并创建适当的唯一索引。无论如何,CurrentState.ID将很少使用。但如果你真的想在每张桌子上都有一个ID列,那就适合自己。

答案 2 :(得分:0)

在Walter Mitty的回答的基础上,我将向前迈出一步:假设属于同一StateType的两个StateValue(即具有相同的StateTypeId)不能具有相同的名称,我将删除StateValue中的Id列并取(StateTypeId,name)作为StateValue的复合/连接主键。表CurrentState中的StateValueId然后由StateValueName替换,CurrentState中的对(StateTypeId,StateValueName)引用StateValue的复合主键。必须按照Walter的描述添加CurrentState中的对(EquipmentId,StateTypeId)的唯一性约束。如果此对也用作CurrentState的主键而不是Id,则取决于其他表是否引用CurrentState表的事实。

所以答案是:1)是的,2)不一定

一般提示:Clare Churcher的“开始数据库设计”(以及“数据库专业应用数学”的基础)是一本很好的读物。您也可以在Google图书上查看它。

答案 3 :(得分:0)

同样,StateTypeID的FK什么都不做,并且会产生数据不一致的可能性。

我知道你正试图简化讨论的问题,但这些不同的“状态类型”是什么?如果他们彼此无关,可能将他们全部塞进一张桌子是个坏主意。例如,如果您的位置类型为“建筑1”,“建筑2”和“建筑3”;和一种折旧方法,其值为“30年直线”,“15年余额递减”等;还有一种“需要维护”,其值为“无”,“彻底检修”,“调整”,等等;然后把所有这些无关的东西塞进一张桌子是错的。如果为每个州类型创建一个单独的表,并在每个stateValueId的Equipment表中创建一个单独的列,那么整个问题就会消失。

很大程度上取决于您做或可能做的查询。您是否有任何通过此表结构更简单的查询?或者它们都变得更加复杂,因为你必须测试状态类型和状态值?

如果你这样做的唯一原因是因为创建更多的表似乎很痛苦,那就错了。

如果您使用较少的编辑屏幕,我建议创建一个通用的编辑程序,可以将状态类型表名作为参数。