SQL Server表约束设计

时间:2014-07-09 00:34:51

标签: sql sql-server

我有一个SQL服务器表的设计问题 我在桌子上有设备如下:

Table Equipments
id int PK
idCommunications int FK to table Communications (defined below)
Name varchar  

每台设备只能有一种通信系统(表通信)。

Table Communications
id int PK
Name varchar

每个通信系统可以具有任意数量的参数。我不想为每个我知道的通信系统创建一个特定的表,因此我创建了一个列出参数的表

Table ParamCommunications
id int PK
idCommunications int FK to table Communications
Parameter varchar

和另一个包含每个设备的每个参数值的表

Table ConfComEquipment
id int PK
idParamCommunications int FK to table ParamCommunications
idEquipment int FK to table Equipment
Value varchar

该表结构允许我为每个通信系统创建参数列表并将它们分配给一个设备。我发现的问题是,在最后一个表中,我可以输入idParamCommunications的配置,该配置不属于设备定义的相同idCommunications。

例如。我有两个通讯系统

id Name
1 Serial
2 TCP/IP

我在ParamCommunications表中有以下参数:

id idCommunications Parameter
1        1            BaudRate
2        1            COMPort
3        2            IPAddress

表设备有:

id idCommunications Name
1        1           SerialEquipment
2        2           EthernetEquipment

当我对配置表进行配置时,约束不允许我使用任何未定义的设备或未定义的参数,但允许我这样做:

id idCommunications idParamCommunications idEquipment Value
 1      1                   1                2       "somevalue"

id = 2的设备的idCommunications = 2,但在此设置中不是约束。

我知道我有以下潜在的解决方案:

  1. 创建使用设备和通信来定义它的复合主键。这将给我带来的问题是,我需要使用复合链接到一些不关心通信系统的其他表(此处未显示)。
  2. 创建另一个表:CommunicationByEquipment,它将设备链接到其通信系统,然后从ConfComEquipment表中引用该表的PK。
  3. 控制程序端的数据完整性。可能更容易出错和孤儿记录
  4. 我还有其他选择吗?如果没有,你会推荐哪一个?

    感谢您的帮助,感谢抱歉。我打算粘贴显示表格结构的数字,但在获得更高级别之前我不允许这样做。

    生锈

3 个答案:

答案 0 :(得分:1)

主键不是外键目标的唯一可能性 - 任何唯一索引也可以由外键约束作为目标。所以,我认为以下结构强制执行您的要求:

create table Communications (
    ID int not null,
    Name varchar(20) not null,
    constraint PK_Communications PRIMARY KEY (ID),
    constraint UQ_Communication_Names UNIQUE (Name)
)
go
create table CommunicationParameters (
    ID int not null,
    CommunicationID int not null,
    Parameter varchar(20) not null,
    constraint PK_CommunicationParameters PRIMARY KEY (ID),
    constraint UQ_CommunicationParameter_Parameters UNIQUE (Parameter),
    constraint FK_CommunicationParameters_Communications
          FOREIGN KEY (CommunicationID) references Communications (ID),

    constraint UQ_CommunicationParameters_Communication_XRef
          UNIQUE (ID,CommunicationID)
)
go
create table Equipments (
    ID int not null,
    CommunicationID int not null,
    Name varchar(20) not null,
    constraint PK_Equipments PRIMARY KEY (ID),
    constraint UQ_Equipment_Names UNIQUE (Name),
    constraint FK_Equipments_Communications
          FOREIGN KEY (CommunicationID) references Communications (ID),

    constraint UQ_Equipment_Communication_XRef
          UNIQUE (ID,CommunicationID)
)

最后:

create table ConfComEquipment (
    ID int not null,
    CommunicationID int not null,
    CommunicationsParameterID int not null,
    EquipmentID int not null,
    Value varchar(99) not null,
    constraint PK_ConfComEquipment PRIMARY KEY (ID),
    constraint FK_ConfComEquipment_CommunicationParameters
          FOREIGN KEY (CommunicationsParameterID) references
                CommunicationParameters (ID),
    constraint FK_ConfComEquipment_Equipment
          FOREIGN KEY (EquipmentID) references
                Equipments (ID),

    constraint FK_ConfComEquipment_CommunicationParameters_XRef
          FOREIGN KEY (CommunicationsParameterID,CommunicationID) references
                CommunicationParameters (ID,CommunicationID),
    constraint FK_ConfComEquipment_Equipment_XRef
          FOREIGN KEY (EquipmentID,CommunicationID) references
                Equipments (ID,CommunicationID)
)

请注意,在名称的末尾添加了XRef这些约束,允许强制执行约束,即最后一个表中的CommunicationID列与存储在两个中的值一致CommunicationParametersEquipments表,同时将这些表上的主键保留为ID列。

严格来说,现在这使得"真实"外键FK_ConfComEquipment_CommunicationParametersFK_ConfComEquipment_Equipment为冗余,XRef约束就足够了。您是否可以将它们保留在最终的桌面设计中,这是可选的。

答案 1 :(得分:0)

没有声明性约束可以强制执行您指定的完整性规则。使用UNIQUE约束,FOREIGN KEY约束或CHECK约束的任意组合都不能强制执行这些类型的完整性规则。

如果您需要在数据库中/由数据库强制执行这些完整性规则,那么您拥有的选项是:1)实现触发器(在执行DML操作时触发)和/或2)实现存储过程(代替DML(INSERT / UPDATE / DELETE)操作调用)。

随着完整性规则的发展,这些触发器和/或存储过程将需要维护。正如您所提到的,这个相同的逻辑可以在应用程序中实现,作为应用程序和数据库之间的另一层。

问题的症结在于关系模型和实体 - 属性 - 值(EAV)模型之间的“阻抗不匹配”。

使用EAV模型,我们无法定义任何有用的外键(除了属性值与实体的基本关联之外)。如果尝试将实体和属性值作为单行返回,即从EAV模型转换回看起来像关系中的行的形式,则查询更复杂,数量级更复杂模型。

答案 2 :(得分:0)

鉴于上述信息,我认为如果您在设备表设计中进行一次初步更改,设备和参数之间的多对多关系可能会起作用:

  1. 由于每种类型的设备只有一种类型的通信系统,只需将通信系统添加到设备表中(通过这样做,您的参数现在是设备的属性而不是通信系统)
  2. (可选)构建一个定义各种通信系统的表 在下拉列表中使用它。
  3. (这里有两个选项)
    • a.build一个只定义规范名称的表(将值放在多对多中)。不建议使用,因为规格变得更加动态。
    • b。建立一个定义所有参数/规格的表格
  4. 构建一个将设备连接到参数的表(这是多对多关系)
  5. 1.表:设备
      - pk
      - fk_comm_sys(下拉comm sys定义)
      - 姓名

    2.Table:comm_sys_defined
      - pk
      - 名称(以太网/串行/等)   - 等

    3a.Table:parameters_defined
      - pk
      - 名称(例如波特率)
    注意:在此方案中,值存储在多对多表

    3B。表:parameters_defined
      - pk
      - 名称(名称:波特率)
      - 等(值:速度,等级,范围等)

    4a.Table:equip_parameters
      - pk
      - fk_equip
      - fk_parameters(name)
      - 速度(值)
    注意:严格来说,这不是2NF

    4b中。表:equipment_parameters
      - pk(考虑复合键)
      - fk_equipment
      - fk_parameter
    注意:如果您希望避免重复,则需要在此处使用复合键