Question

I have a four tables, which look a bit like this:

CREATE TABLE [TableA]
    ( [ID]    INT     NOT NULL IDENTITY (1, 1) PRIMARY KEY )
CREATE TABLE [TableB]
    ( [A_ID]  INT     NOT NULL FOREIGN KEY REFERENCES [TableA] ([ID]) 
    , [Value] TINYINT NOT NULL 
    , PRIMARY KEY ( [A_ID], [Value] ) )
CREATE TABLE [TableC]
    ( [ID]    INT     NOT NULL IDENTITY (1, 1) PRIMARY KEY
    , [A_ID]  INT     NOT NULL FOREIGN KEY REFERENCES [TableA] ([ID]) )
CREATE TABLE [TableD]
    ( [ID]    INT     NOT NULL IDENTITY (1, 1) PRIMARY KEY
    , [C_ID]  INT     NOT NULL FOREIGN KEY REFERENCES [TableC] ([ID])
    , [Value] TINYINT NOT NULL )

But I'd like to enforce referential integrity on TableD such that a valid value may only be one of the values from TableB of the TableA associated with the parent TableC record. For example:

TableA: ID 
         1
TableB: A_ID | VALUE
           1 |     1
           1 |     2
TableC: ID | A_ID
         7 |    1
TableD: ID | C_ID | VALUE
         1 |    7 |     1 -- Fine, Inserted
         1 |    7 |     2 -- Fine, Inserted
         1 |    7 |     3 -- Invalid, Rejected!

Now, I tried adding an A_ID column to TableD like this:

CREATE TABLE [TableD]
    ( [ID]    INT     NOT NULL IDENTITY (1, 1) PRIMARY KEY
    , [C_ID]  INT     NOT NULL 
    , [A_ID]  INT     NOT NULL 
    , [Value] TINYINT NOT NULL
    , FOREIGN KEY ([C_ID], [A_ID]) REFERENCES [TableC] ([ID], [A_ID])
    , FOREIGN KEY ([A_ID], [Value]) REFERENCES [TableB] ([A_ID], [Value]) )

But I get the following error:

Msg 1776, Level 16, State 0, Line 2
There are no primary or candidate keys in the referenced table 'TableC' that match the referencing column list in the foreign key 'FK__TableD__TableC'.

Msg 1750, Level 16, State 0, Line 2
Could not create constraint. See previous errors.

I don't really like this solution anyway because it seems denormalized—since I have the TableCTableA relationship stored in two different places—but I can't think of any other way to enforce referential integrity (other than triggers, which I'd like to avoid).

Is there any way to achieve this?

Was it helpful?

Solution

Yes, there is a way. You can add unique constraint to table TableC:

CREATE TABLE [TableC]
    ( [ID]    INT     NOT NULL IDENTITY (1, 1) PRIMARY KEY
    , [A_ID]  INT     NOT NULL FOREIGN KEY REFERENCES [TableA] ([ID]),
     CONSTRAINT UK_TableC UNIQUE ([ID], [A_ID]) )

and then you will be able referencing TableC in table TableD as you specified:

CREATE TABLE [TableD]
    ( [ID]    INT     NOT NULL IDENTITY (1, 1) PRIMARY KEY
    , [C_ID]  INT     NOT NULL 
    , [A_ID]  INT     NOT NULL 
    , [Value] TINYINT NOT NULL
    , FOREIGN KEY ([C_ID], [A_ID]) REFERENCES [TableC] ([ID], [A_ID])
    , FOREIGN KEY ([A_ID], [Value]) REFERENCES [TableB] ([A_ID], [Value]) )
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top