The best you can achieve using SQL FOREIGN KEY
constraints is to ensure that each mortgage type appears at most once in each subtype table, a one-to-zero-or-one relationship, if you will. One way to enforce this constraint is to use a two-column composite key on { ID , type }
to be used throughout the schema and allowing the type
to be tested in subtable constraints. Here's a rough sketch using two mortgage subtypes (curly braces indicate a list with no implied order):
Mortgages { mortgage_ID , mortgage_type }
KEY { mortgage_ID }
KEY { mortgage_ID , mortgage_type }
CONSTRAINT mortgage_type = 'Tracker'
OR mortgage_type = 'Fixed'
FixedRateMortgages { mortgage_ID , mortgage_type , fixed_rate }
KEY { mortgage_ID , mortgage_type }
FOREIGN KEY { mortgage_ID , mortgage_type } REFERENCES Mortgages
CONSTRAINT mortgage_type = 'Fixed';
FixedRateMortgages { mortgage_ID , mortgage_type , base_rate , track_rate }
KEY { mortgage_ID , mortgage_type }
FOREIGN KEY { mortgage_ID , mortgage_type } REFERENCES Mortgages
CONSTRAINT mortgage_type = 'Tracker';
Clients { client_ID }
KEY { client_ID } ;
Agreements { mortgage_ID , mortgage_type , client_ID }
KEY { mortgage_ID , mortgage_type , client_ID }
FOREIGN KEY { mortgage_ID , mortgage_type } REFERENCES Mortgages
FOREIGN KEY { client_ID } REFERENCES Client;
You did not specify a SQL product. Strict one-to-one referential integrity may be maintained in Standard SQL-92 using CREATE ASSERTION
constraints declared as DEFERRABLE INITIALLY DEFERRED
to encapsulate this 'distributed' one per subtype table logic. A SQL statment could then, in a tranasction, defer the ASSERTION
s, modify referenced and referencing tables then reapply the ASSERTION
s (or do this automatically by committing the transaction). Sadly, there are no real life SQL products that support CREATE ASSERTION
. There are workarounds depending on vendor e.g. triggers, a table expression in a SQL function called from a row-level CHECK
constraint, revoking write privileges from the tables then forcing users to update the tables via CRUD procedures that ensure referential integrity, etc.
That said, it is usually acceptable in SQL to have one-to-zero-or-one relationships and indeed there may be advantages to doing so e.g. to make database constraints easier to write (and therefore fewer bugs), flexibility of not forcing users to use one set of procedures, etc.