数据库设计 - 如何使用代理键对表强制执行外键约束

时间:2010-09-30 06:41:40

标签: database-design foreign-keys surrogate-key

我的表架构是这样的

1。主表:条款

  1. ClauseID =代理人pk(身份)
  2. ClauseCode = nvarchar用户指定值
  3. Class = nvarchar FK到主类表
  4. 等...
  5. ClauseCode + Class =此表的候选键

    2。主表:GroupClause

    1. GroupClauseID =代理人pk(身份)
    2. GroupClauseCode = nvarchar用户指定值
    3. Class = nvarchar FK到主类表 等...
    4. GroupClauseCode + Class =此表的候选键

      第3。事务/映射表:: GroupClause_Clause_Mapping :此表将每个组子句映射到多个单独的子句

      1. GroupClauseID = FK to GroupClause PK
      2. ClauseID = FK to Clause PK
      3. 等...
      4. 要求:每个组子句只能映射到与自身属于同一个类的子句

        问题:上述表格设计不会在数据库级别强制执行该要求。

        一种可能的解决方案:表* GroupClause_Clause_Mapping *有列

        1. ClauseCode
        2. GroupClauseCode
        3. 班级
        4. 其中我可以创建ClauseCode + Class作为子句表的FK以及GroupClauseCode + Class作为FK到GroupClause表。

          但是,如果我这样做,那么代理身份密钥就没用了,我也可以摆脱它们

          我的设计是否存在使用代理键的问题?

          有关如何使用代理键并仍然在数据库级别强制执行约束的任何建议吗?

2 个答案:

答案 0 :(得分:1)

如果代码本身很大/不实用,那么您可能仍然希望使用代理(如果可用)。

由于您只想强制匹配类,因此映射表可以是

ClauseID,
GroupClauseID,
Class (or possibly ClassID)

对于主表,您仍然具有PK(ClauseID)和唯一约束(ClauseID,Class)。然后,您可以决定是仅使用FK(ClauseID,Class)还是在映射表和每个主表之间有两个FK(实际上,您可以说一个FK是外键引用,另一个是执行你的规则。)

我的一个数据库中有类似的设置(想想调查系统):

CREATE TABLE [dbo].[DataItems](
    [DataItemID] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
    [TypeRequired] [varchar](10) NOT NULL,
    [Name] [varchar](50) NOT NULL,
    /* Other Columns */
 CONSTRAINT [PK_DataItems] PRIMARY KEY NONCLUSTERED 
(
    [DataItemID] ASC
),
 CONSTRAINT [UX_DataItems_ClientAnswerFKTarget] UNIQUE CLUSTERED 
(
    [DataItemID] ASC,
    [TypeRequired] ASC
),
 CONSTRAINT [UX_DataItems_Name] UNIQUE NONCLUSTERED 
(
    [Name] ASC
)
)

CREATE TABLE [dbo].[ClientAnswers](
    [ClientAnswersID] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
    [ClientID] [uniqueidentifier] NOT NULL,
    [DataItemID] [uniqueidentifier] NOT NULL,
    [TypeRequired] [varchar](10) NOT NULL,
    [BoolValue] [bit] NULL,
    [IntValue] [int] NULL,
    [CharValue] [varchar](6500) NULL,
    [CurrencyValue] [int] NULL,
    [DateValue] [datetime] NULL,
    /* Other Columns */
 CONSTRAINT [PK_ClientAnswers] PRIMARY KEY CLUSTERED 
(
    [ClientID] ASC,
    [DataItemID] ASC
)
)
GO
ALTER TABLE [dbo].[ClientAnswers] ADD  CONSTRAINT [FK_ClientAnswers_DataItems] FOREIGN KEY([DataItemID],)
REFERENCES [dbo].[DataItems] ([DataItemID])
ON UPDATE CASCADE
GO
ALTER TABLE [dbo].[ClientAnswers] ADD  CONSTRAINT [FK_ClientAnswers_DataItems_TypesMatch] FOREIGN KEY([DataItemID],TypeRequired)
REFERENCES [dbo].[DataItems] ([DataItemID],TypeRequired)
GO

然后我更进一步,有更多约束,确保type列匹配非null * Value列

答案 1 :(得分:0)

“如果我这样做,那么代理身份密钥就没用了,我也可以摆脱它们。”

这是对的。这是使用自然键而不是代理项的一个原因:当您需要使用自然键值实现一些额外的约束或逻辑时。

您可能希望从其他表中引用代理项,以便代理键仍然有用。如果你根本不使用代理,那么最好放弃它。代理键通常意味着一定的开销,因为它们通常被编入索引,这可能会损害插入的性能。