I have a table which needs to link one of three seperate tables, but it should only link to one of them, e.g.
Main_Table
id UNIQUEIDENTIFIER
t1_id UNIQUEIDENTIFIER
t2_id INT
t3_id INT
T1
id UNIQUEIDENTIFIER
name VARCHAR(255)
T2
id INT
name VARCHAR(255)
T3
id INT
name VARCHAR(255)
Is it possible to have a constraint whereby only one of t1, t2 or t3 is not null at any one time?
Is this just bad design? If so, what suggestions would you make for the design?
EDIT:
I’ve been asked to elaborate the reasons behind this particular design.
Main_Table is attempting to be a payer table, which could reference either an individual user (T1), a group of individual users (T2), or a group of groups (T3).
This is a database design I’ve inherited, and it isn’t really subject to change unfortunately.
My biggest problem is that I need to associate between different types, so a type field won’t work here as the indexes are different.
The design you’re describing is called exclusive arcs. Yes, it’s a pretty fragile design and even fails some rules of normalization.
Here’s an alternative:
With this design, each row in
Main_Tablemust reference one row inT0.Likewise, each row in
T0can be the parent of only one row inT1,T2, orT3.This is a way to implement Class Table Inheritance and Polymorphic Associations without breaking referential integrity.
Right, so think of this in terms of object-oriented design. If you had three classes that could function as a recipient of payments, you’d create a interface called
Payableor something, so that each you could rely on typing those objects. AllPayableobjects must have asendPayment()method for instance. In some OO languages, the interface is a superclass and is called an abstract class or a pure virtual class.The
T0table functions as a common type for each of the child tablesT1,T2, andT3. WhenMain_Tablehas a foreign key toT0, it’s like sayingMain_Tablemust have a reference to some entity that isPayable, but any object descending from that superclass is okay to use.The
typecolumn is just a trick to make sure that a givenT0.idcan be referenced only by one subclass table at a time. It’s kind of optional, if you can rely on your application logic to insert a given child row into only one of the subclass tables.Also see the section on Polymorphic Associations in my presentation “SQL Antipatterns Strike Back.”