2012-02-10 1 views
1

У меня есть таблица под названием Message. Каждое сообщение может быть связано с таблицей Invoice или с таблицей Rfp, но не с обоими. Я изо всех сил с наиболее оптимальным образом реализовать это:Нужны советы по внешним ключам для альтернативных таблиц

  1. Один подход для Message таблицы имеют внешние ключи для обеих Invoice и Rfp таблиц. Один FK будет действителен, а другой должен быть NULL. (Наследование на одном столе.) Но это кажется довольно неудобным. В дополнение к неиспользуемому столбцу мне нужно найти способы предотвратить случаи, когда используются FK либо оба, либо оба значения NULL. И это нужно будет повторять для каждого отдельного сообщения.

  2. Другой подход заключается в создании соединительной таблицы. В этом случае моя таблица Message будет иметь FK для таблицы соединения, а таблицы Invoice и Rfp также будут иметь FK для таблицы соединения. Однако проблема заключается в том, что, учитывая ссылку на таблицу соединений, неудобно находить связанную таблицу Invoice или Rfp, потому что я не знаю, что содержит FK. Итак, здесь мне нужно прибегнуть к другим шагам, чтобы узнать, как найти связанную таблицу, например, добавить столбец, чтобы обозначить, какая таблица связана, для которого трудно создать ограничение.

  3. Наконец, я мог бы создать два типа таблиц Message. Это решает проблемы, описанные выше, но это создает проблемы для нашего приложения, потому что у нас есть логика в местах, где нужно добавлять сообщения, не зная, какой тип они есть. (Мы можем иметь только FK в соответствующей таблице.)

Может кто-нибудь предложить здесь несколько советов. Ни один из этих способов не идеален, но, возможно, есть аспекты, которые я не рассматривал при выборе между ними. Или, может быть, есть лучший подход.

+0

Я обычно идут с опцией нет. 1 - да, в итоге у вас есть два столбца FK, по крайней мере один из которых всегда равен нулю - но это самый чистый и ясный подход, на мой взгляд. Из столбцов FK видно, что вы имеете в виду, и вы можете иметь ссылочную целостность для этих ограничений FK. –

+0

@marc_s: Но не был бы вариант-2 еще более понятным (нормализованным) подходом? С таблицей «joining» должен быть супертип двух таблиц подтипа 'Invoice' и' Rfp'? –

+0

Вариант-2 будет [Concrete Supertable] (http://stackoverflow.com/questions/922184/why-can-you-not-have-a-foreign-key-in-a-polymorphic-association) пример в Ответ Билла Карвина в этом вопросе. –

ответ

2

В варианте 1, вы можете использовать проверочное ограничение для обеспечения только один FK установлен ...

CREATE TABLE [dbo].[Rfp] (Id int IDENTITY(1,1) NOT NULL, PRIMARY KEY CLUSTERED (Id)) 
CREATE TABLE [dbo].[Invoice] (Id int IDENTITY(1,1) NOT NULL, PRIMARY KEY CLUSTERED (Id)) 

CREATE TABLE dbo.[Message] (Id int IDENTITY(1,1) NOT NULL, RfpId int, InvoiceId int, 
    PRIMARY KEY CLUSTERED (Id), 
    FOREIGN KEY (RfpId) REFERENCES [dbo].[Rfp] (Id), 
    FOREIGN KEY (InvoiceId) REFERENCES [dbo].[Invoice] (Id), 
    ) 

ALTER TABLE dbo.[Message] 
    ADD CONSTRAINT CK_FK CHECK ( (RfpId IS NULL AND InvoiceId IS NOT NULL) 
            OR (RfpId IS NOT NULL AND InvoiceId IS NULL));