Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/85.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL数据库设计问题_Sql_Database Design - Fatal编程技术网

SQL数据库设计问题

SQL数据库设计问题,sql,database-design,Sql,Database Design,目前我正在处理一个数据库设计问题,我将介绍一个简化的场景: 假设我有四个表、设备、CurrentState、StateValue和StateType,具有以下模式: Equipment ------------ Id (PK), Name CurrentState ------------ Id (PK), EquipmentId (FK) (IX), StateValueId (FK), StateTypeId (FK) (IX) StateValue ------------ Id

目前我正在处理一个数据库设计问题,我将介绍一个简化的场景:

假设我有四个表、设备、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
一台设备可以具有属于不同状态类型的多个不同的当前状态,因此具有唯一索引(IX)。StateType基本上是一个状态机,StateValue包含每个状态机的值

现在,我的问题是关于CurrentState和StateValue表中的StateTypeId外键,它们确定CurrentState记录是什么StateType和StateValue记录是什么StateType

首先,就引用完整性而言,这种类型的关系设计糟糕吗?我的猜测是,这是一个糟糕的设计,因为CurrentState表和StateType表之间应该只有一个链接,这是通过StateValue实现的,否则CurrentState记录可能会有两个不同的StateType(一个通过direct FK,另一个通过StateValue表FK)

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


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

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


当然,如果您坚持在
CurrentState
中使用
StateTypeId
,您可以设置
check
约束,以确保
StateTypeId
等于
StateValueId
中的
StateTypeId
。但这确实是迂回的。将它们都放在各自的存储库中会更干净、更易于维护。

您的设计问题不是由于表中的列设计造成的。从性能和灵活性的角度来看,您可以保留在建议的解决方案中显示的相同列,并获得更好的结果

您需要做的是在CurrentState和StateValue之间设置一个复合引用约束,并删除CurrentState和StateType之间的引用约束。(我在您的问题陈述中没有看到该约束,但我从您使用的“FK”中推测出来。)我忘记了复合引用约束的语法(它可能是DBMS特有的),但它类似于

约束ValidState FOREIGNKEY(StateValueId,StateTypeId)引用StateValue(Id,StateTypeId)

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

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

在CurrentState(设备ID、StateTypeId)上创建唯一索引CurrentStateIDX


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

基于Walter Mitty的回答,我会向前走一步:假设属于同一StateType(即,具有相同StateTypeId)的两个StateValue不能有相同的名称,我会将ID列放在StateValue中,然后取(StateTypeId,name)作为StateValue的复合/连接主键。然后,表CurrentState中的StateValueId被StateValueName替换,CurrentState中的对(StateTypeId,StateValueName)引用StateValue的复合主键。如Walter所述,必须在CurrentState中添加对(EquipmentId,StateTypeId)的唯一性约束。如果此对还用作CurrentState的主键而不是Id,则取决于其他表是否引用CurrentState表

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


一般提示:克莱尔·丘吉尔(Clare Churcher)的《开始数据库设计》(以及在此基础上的《数据库专业人士应用数学》)是一本极好的读物。您还可以在Google Books上查看它。

同样,StateTypeID的FK没有任何作用,并且可能会产生不一致的数据

我知道你试图简化问题以供讨论,但这些不同的“状态类型”是什么?如果他们彼此无关,也许把他们都塞进一张桌子是个坏主意。例如,如果您的位置类型的值为“Building 1”、“Building 2”和“Building 3”;采用“30年直线法”、“15年余额递减法”等折旧方法;以及一种“需要维护”类型,其值为“无”、“完全大修”、“调谐”等等;然后把所有这些不相关的东西塞进一张桌子是错误的。如果为e创建单独的表