patternsqlModerate
Conditional Foreign Key Relationship
Viewed 0 times
keyforeignconditionalrelationship
Problem
I currently have a foreign key between two entities, and I would like to make that relation conditional to the entityType of one of the tables. Here's the hierachy of tables, this is done via FK refrences from child to parent
I currently have a FK relation from Employee to store
I would like to add the conditional:
Is this possible or must I subclass TransactionalStores into two new subTypes (e.g. PhysicalStores and VirtualStores)
Store
/ \
Employees \
TransactionalStores
/ | \
Kiosks | BrickMortars
OnlinesI currently have a FK relation from Employee to store
ALTER TABLE Employees ADD CONSTRAINT Employee_Store
FOREIGN KEY (TransStoreId)
REFERENCES TransactionalStores(StoreId)I would like to add the conditional:
WHERE TransactionalStores.storeType != 'ONLINE_TYPE'Is this possible or must I subclass TransactionalStores into two new subTypes (e.g. PhysicalStores and VirtualStores)
Solution
Foreign keys can be made conditional...sort of. You don't show the layout of each table, so here is a typical design showing your relationships:
The Onlines and BrickMorters would have the same basic structure but with StoreType constrained to only 'O' or 'B' as appropriate.
Now you want a reference from another table to TransactionalStores (and through it to the various store tables) but limited to Kiosks and BrickMorter. The only difference would be in the constraint:
In this table, the FK reference forces StoreType to be either 'K', 'O' or 'B' but the field constraint further limits it to only 'K' or 'B'.
For illustration, I've used a check constraint to limit the store types in the TransactionStores table. In real life, a StoreTypes lookup table with StoreType being a FK to that table would probably be a better design choice.
create table TransactionalStores(
ID int not null auto_increment,
StoreType char not null,
..., -- other data
constraint CK_TransStoreType check( StoreType in( 'B', 'K', 'O' )),
constraint PK_TransactionalStores primary key( ID ),
constraint UQ_TransStoreTypes unique( ID, StoreType ) -- for FK references
);
create table Kiosks(
ID int not null,
StoreType char not null,
..., -- other Kiosk data
constraint CK_KioskStoreType check( StoreType = 'K' ), -- kiosks only
constraint PK_Kiosks primary key( ID, StoreType ),
constraint FK_Kiosks_TransStores foreign key( ID, StoreType )
references TransactionalStores( ID, StoreType )
);The Onlines and BrickMorters would have the same basic structure but with StoreType constrained to only 'O' or 'B' as appropriate.
Now you want a reference from another table to TransactionalStores (and through it to the various store tables) but limited to Kiosks and BrickMorter. The only difference would be in the constraint:
create table Employees(
ID int not null,
StoreID int,
StoreType char,
..., -- other Employee data
constraint PK_Employees primary key( ID ),
constraint CK_Employees_StoreType check( coalesce( StoreType, 'X' ) <> 'O' )), -- Online not allowed
constraint FK_Employees_TransStores foreign key( StoreID, StoreType )
references TransactionalStores( ID, StoreType )
);In this table, the FK reference forces StoreType to be either 'K', 'O' or 'B' but the field constraint further limits it to only 'K' or 'B'.
For illustration, I've used a check constraint to limit the store types in the TransactionStores table. In real life, a StoreTypes lookup table with StoreType being a FK to that table would probably be a better design choice.
Code Snippets
create table TransactionalStores(
ID int not null auto_increment,
StoreType char not null,
..., -- other data
constraint CK_TransStoreType check( StoreType in( 'B', 'K', 'O' )),
constraint PK_TransactionalStores primary key( ID ),
constraint UQ_TransStoreTypes unique( ID, StoreType ) -- for FK references
);
create table Kiosks(
ID int not null,
StoreType char not null,
..., -- other Kiosk data
constraint CK_KioskStoreType check( StoreType = 'K' ), -- kiosks only
constraint PK_Kiosks primary key( ID, StoreType ),
constraint FK_Kiosks_TransStores foreign key( ID, StoreType )
references TransactionalStores( ID, StoreType )
);create table Employees(
ID int not null,
StoreID int,
StoreType char,
..., -- other Employee data
constraint PK_Employees primary key( ID ),
constraint CK_Employees_StoreType check( coalesce( StoreType, 'X' ) <> 'O' )), -- Online not allowed
constraint FK_Employees_TransStores foreign key( StoreID, StoreType )
references TransactionalStores( ID, StoreType )
);Context
StackExchange Database Administrators Q#113122, answer score: 19
Revisions (0)
No revisions yet.