How to express this constraint in a database schema?
In a nutshell, introduce d
into the third table to enable vanilla foreign key constraints e.g. Transitional SQL-92 syntax:
CREATE TABLE T1
(
a INTEGER NOT NULL,
d INTEGER NOT NULL,
UNIQUE (a, d)
);
CREATE TABLE T2
(
b INTEGER NOT NULL,
d INTEGER NOT NULL,
UNIQUE (b, d)
);
CREATE TABLE T3
(
a INTEGER NOT NULL,
b INTEGER NOT NULL,
c INTEGER NOT NULL,
d INTEGER NOT NULL,
UNIQUE (a, b, c),
FOREIGN KEY (a, d) REFERENCES T1 (a, d),
FOREIGN KEY (b, d) REFERENCES T2 (b, d)
);
" So is your answer "it's not possible"? "
Many things are possible. In your very particular case, it looks to me like enforcing your 'additional' constraint can be achieved by keeping the database single-table (4-column). This will guarantee you that any combined a,b will always correspond to the same d (because there can only ever be one single d). The price you pay is that there is no longer a "natural" way (i.e. one that is an immediate consequence of the very logical structure of the database itself) that will enforce your a->d and b->d FDs "automatically".
It is a well-known fact that the classical process of normalization-through-decomposition, sometimes requires that certain FDs be reinstated as a database constraint, because in the decomposed design the rule can no longer be stated as an FD. Your particular case seems to be one such, where you have the choice between a design that "automatically" enforces a->d and b->d, but where you have to do extra effort to enforce your additional constraint, or a design that "automatically" enforces your additional constraint, but where you have to do extra work to enforce [the constraints corresponding to] your a->d and b->d FDs.
Having ALL the constraints you mention enforced merely by database structure, is possible, in your particular case, using onedaywhen's solution. However, (a) that is only a solution for particular cases such as your example, (b) the price you pay is increased redundancy, and therefore additional complexity in updating your database (and certain updates might be impossible to achieve !!!), and (c) it still remains a fact that not all conceivable database constraints are expressible as an FD.
(Sorry for posting a second answer. My Stackoverflow login doesn't allow me to comment here.)
In a nutshell, create an ASSERTION
to ensure that at no time can the business rule be violated e.g. Full Standard SQL-92 syntax:
CREATE TABLE T1
(
a INTEGER NOT NULL,
d INTEGER NOT NULL,
UNIQUE (a, d)
);
CREATE TABLE T2
(
b INTEGER NOT NULL,
d INTEGER NOT NULL,
UNIQUE (b, d)
);
CREATE TABLE T3
(
a INTEGER NOT NULL,
b INTEGER NOT NULL,
c INTEGER NOT NULL,
UNIQUE (a, b, c)
);
CREATE ASSERTION no_a_and_b_should_be_combined_with_a_c_where_a_and_b_have_different_ds
CHECK (
NOT EXISTS (
SELECT *
FROM T3
WHERE NOT EXISTS (
SELECT T1.d
FROM T1
WHERE T1.a = T3.a
INTERSECT
SELECT T2.d
FROM T2
WHERE T3.b = T3.b
)
)
);
The bad news is that no commercial (or otherwise?) SQL product supports CREATE ASSERTION
.
Most industrial-strength SQL products support triggers: one could implement the above in a trigger on each applicable table. MS Access is the only commercial product I know of that supports subqueries in CHECK
constraints but I don't consider it to be industrial-strength. There are further workarounds e.g. forcing users to update tables only via stored procedures that can be shown to never leave the database in an illegal state.