SQL中的条件外键

时间:2010-12-23 14:32:05

标签: sql-server sql-server-2008 database-design

我有一个名为PartyChannel的表,其中包含以下列

 ID, ChannelID, ChannelType

ChannelID存储MailIDPhoneIDEmailID,具体取决于ChannelType

那么如何在PartyChannel和所有三个表(邮件,电子邮件和电话)之间创建一个外键,具体取决于channelType。

3 个答案:

答案 0 :(得分:10)

您可以将PERSISTED COMPUTED列与case语句一起使用,但最后,它只会为您购买开销。

最好的解决方案是将它们建模为三个不同的值。

CREATE TABLE Mails (MailID INTEGER PRIMARY KEY)
CREATE TABLE Phones (PhoneID INTEGER PRIMARY KEY)
CREATE TABLE Emails (EmailID INTEGER PRIMARY KEY)

CREATE TABLE PartyChannel (
  ID INTEGER NOT NULL
  , ChannelID INTEGER NOT NULL
  , ChannelType CHAR(1) NOT NULL
  , MailID AS (CASE WHEN [ChannelType] = 'M' THEN [ChannelID] ELSE NULL END) PERSISTED REFERENCES Mails (MailID)
  , PhoneID AS  (CASE WHEN [ChannelType] = 'P' THEN [ChannelID] ELSE NULL END) PERSISTED REFERENCES Phones (PhoneID)
  , EmailID AS  (CASE WHEN [ChannelType] = 'E' THEN [ChannelID] ELSE NULL END) PERSISTED REFERENCES Emails (EmailID)
)

<强>声明

只是因为你并不意味着你应该这样做。

答案 1 :(得分:4)

AFAIK,您无法使用标准外键执行此操作。但是,您可以通过使用触发器实现某些操作来帮助确保数据完整性。本质上,只要引用表上有插入或更新,触发器就会检查引用表上是否存在“外键” - 必须存在的值。同样,从引用的表中删除可能会有一个触发器,用于检查使用要删除的键的引用表上的记录。

更新:虽然我选择了“回答”,但我同意@onedaywhen留下的评论,这实际上是一个设计引起的问题,应该让你重新考虑你的设计。也就是说,您应该有三个不同的列,而不是一个引用三个表的列。当一个填充时,您只需将其他两列保留为null,这反过来会让您使用标准外键。任何担心这会“占用太多空间”都是愚蠢的;它代表了一个过早优化的严重情况 - 它并不重要。

答案 2 :(得分:4)

Email, Mail, Phone的子类型Channel

alt text