I have a design question for SQL server tables.
I have equipments in a table as follows:
Table Equipments
id int PK
idCommunications int FK to table Communications (defined below)
Name varchar
Each equipment can have only one type of communications system (table Communications).
Table Communications
id int PK
Name varchar
Each communication system can have an arbitrary number of parameters. I don't want to create an specific table for each communications system I know as they evolve so I created a table that list the parameters
Table ParamCommunications
id int PK
idCommunications int FK to table Communications
Parameter varchar
and another table that contains the value of each parameter for each equipment
Table ConfComEquipment
id int PK
idParamCommunications int FK to table ParamCommunications
idEquipment int FK to table Equipment
Value varchar
This table structure allows me to create the list of parameters for each communication system and assign them to one equipment. The problem I found is that in the last table I can enter a configuration for an idParamCommunications that does not belong to the same idCommunications that the equipment gets defined.
For example. I have two communications systems
id Name
1 Serial
2 TCP/IP
and I have the following parameters in table ParamCommunications:
id idCommunications Parameter
1 1 BaudRate
2 1 COMPort
3 2 IPAddress
The table Equipment have:
id idCommunications Name
1 1 SerialEquipment
2 2 EthernetEquipment
When I do the config the table the constraints won't allow me to use any undefined equipment or undefined parameter but will allow me to do this:
id idCommunications idParamCommunications idEquipment Value
1 1 1 2 "somevalue"
Equipment with id=2 has an idCommunications = 2 but in this setup that is not a constraint.
I understand I have the following potential solutions:
Is there another option I don't see? If not, which one would you recommend?
Thanks for your help and sorry for the long post. I was going to paste figures showing the table structure but I'm not allowed until I get a higher rank.
Rusty
Primary keys aren't the only possibility for the target of a foreign key - any unique index can also be targeted by a foreign key constraint. So, I think the below structure enforces your requirements:
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)
)
And finally:
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)
)
Note that it is the addition of these constraints with XRef
at the end of their names that allows is to enforce the constraint that the CommunicationID
column in this last table agrees with the values stored in both the CommunicationParameters
and Equipments
tables, whilst leaving the primary keys on these tables as just the ID
column.
Strictly, this now makes the "real" foreign keys, FK_ConfComEquipment_CommunicationParameters
and FK_ConfComEquipment_Equipment
as redundant, the XRef
constraints are sufficient. It's optional whether you keep these still in your final table design.
There are no declarative constraints that will enforce the integrity rules you specified. These types of integrity rules cannot be enforced with any combination of UNIQUE constraints, FOREIGN KEY constraints or CHECK constraints.
If you need these integrity rules enforced in/by the database, the options you have are to either 1) implement triggers (to be fired when DML operations are performed) and/or 2) implement stored procedures (to be called in place of DML (INSERT/UPDATE/DELETE) operations).
And those triggers and/or stored procedures will require maintenance, as the integrity rules evolve. As you mentioned, this same logic could be implemented in the application, as another layer between the application and the database.
The crux of the problem is the "impedance mismatch" between the relational model and the Entity-Attribute-Value (EAV) model.
With the EAV model, we can't define any useful foreign keys (apart from the elementary association of attribute values to entities). And the queries are more complex, and order of magnitude more complex, if the attempt to return an entity and the attribute values as a single row, that is, to convert from the EAV model back into a form that looks like rows from a relational model.
Given the information above I think a many-to-many relationship might work between equipment and parameters if you make one initial change in the equipment table design:
1.Table: Equipment
- pk
- fk_comm_sys (drop down comm sys defined)
- name
2.Table: comm_sys_defined
- pk
- name (ethernet/serial/etc.)
- etc.
3a.Table: parameters_defined
- pk
- name (eg baud rate)
note: in this scenario values are stored in the many-to-many table
3b. Table: parameters_defined
- pk
- name (name: baud rate)
- etc (value: speed, classes, range, etc.)
4a.Table: equip_parameters
- pk
- fk_equip
- fk_parameters (name)
- speed (value)
Note: strictly speaking this isn't 2NF
4b. Table: equipment_parameters
- pk (consider a composite key)
- fk_equipment
- fk_parameter
Note: if you wish to avoid dups you will need a composite key here
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.