My table schema is something like this
1. Master table : Clause
Columns
- ClauseID = surrogate pk (identity)
- ClauseCode = nvarchar user specified value
- Class = nvarchar FK to a master class table
- etc…
ClauseCode + Class = candidate key for this table
2. Master table : GroupClause
Columns
- GroupClauseID = surrogate pk (identity)
- GroupClauseCode = nvarchar user specified value
- Class = nvarchar FK to a master class table
etc…
GroupClauseCode + Class = candidate key for this table
3. Transaction / Mapping table :: GroupClause_Clause_Mapping : this table maps each group clause to multiple individual clauses
Columns
- GroupClauseID = FK to GroupClause PK
- ClauseID = FK to Clause PK
- etc…
Requirement : Each Group clauses can only be mapped to clauses belonging to the same class as itself
Issue : This above table design does not enforce that requirement at a DB level.
One possible solution : Table *GroupClause_Clause_Mapping* has columns
- ClauseCode
- GroupClauseCode
- Class
wherein i can create ClauseCode + Class as FK to clause table as well as GroupClauseCode
+ Class as FK to GroupClause table.
However, if i do it this way, then the surrogate identity keys are useless and i might as well get rid of them.
Is there an issue with my design using the surrogate keys?
Any suggestions as to how i can use the surrogate keys and still enforce my constraint at a DB level?
If the Codes themselves are large/unwieldy, then you may still want to use the surrogates, where available.
Since you only want to enforce the classes matching, then your mapping table could be
For your master tables, you’d still have PK (ClauseID), and a unique constraint (ClauseID, Class). You can then decide whether to just FK (ClauseID,Class) or to have two FKs between the mapping table and each master table (effectively, you’d then be saying that one FK is the foreign key reference, and the other is there to enforce your rules).
I’ve got a similar setup in one of my databases (think survey system):
And then I go further and have more constraints ensuring that the type column matches the non-null *Value column