我有一个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,但在此设置中不是约束。
我知道我有以下潜在的解决方案:
我还有其他选择吗?如果没有,你会推荐哪一个?
感谢您的帮助,感谢抱歉。我打算粘贴显示表格结构的数字,但在获得更高级别之前我不允许这样做。
生锈
答案 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
列与存储在两个中的值一致CommunicationParameters
和Equipments
表,同时将这些表上的主键保留为ID
列。
严格来说,现在这使得"真实"外键FK_ConfComEquipment_CommunicationParameters
和FK_ConfComEquipment_Equipment
为冗余,XRef
约束就足够了。您是否可以将它们保留在最终的桌面设计中,这是可选的。
答案 1 :(得分:0)
没有声明性约束可以强制执行您指定的完整性规则。使用UNIQUE约束,FOREIGN KEY约束或CHECK约束的任意组合都不能强制执行这些类型的完整性规则。
如果您需要在数据库中/由数据库强制执行这些完整性规则,那么您拥有的选项是:1)实现触发器(在执行DML操作时触发)和/或2)实现存储过程(代替DML(INSERT / UPDATE / DELETE)操作调用)。
随着完整性规则的发展,这些触发器和/或存储过程将需要维护。正如您所提到的,这个相同的逻辑可以在应用程序中实现,作为应用程序和数据库之间的另一层。
问题的症结在于关系模型和实体 - 属性 - 值(EAV)模型之间的“阻抗不匹配”。
使用EAV模型,我们无法定义任何有用的外键(除了属性值与实体的基本关联之外)。如果尝试将实体和属性值作为单行返回,即从EAV模型转换回看起来像关系中的行的形式,则查询更复杂,数量级更复杂模型。
答案 2 :(得分:0)
鉴于上述信息,我认为如果您在设备表设计中进行一次初步更改,设备和参数之间的多对多关系可能会起作用:
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
注意:如果您希望避免重复,则需要在此处使用复合键