0

我的表架构是这样的

1.主表:子句

  1. ClauseID = 代理 pk(身份)
  2. ClauseCode = nvarchar 用户指定值
  3. Class = nvarchar FK 到主类表
  4. ETC...

ClauseCode + Class = 此表的候选键

2.主表:GroupClause

  1. GroupClauseID = 代理 pk(身份)
  2. GroupClauseCode = nvarchar 用户指定值
  3. Class = nvarchar FK 到主类表等...

GroupClauseCode + Class = 此表的候选键

3. Transaction / Mapping table :: GroupClause_Clause_Mapping:该表将每个组子句映射到多个单独的子句

  1. GroupClauseID = FK 到 GroupClause PK
  2. ClauseID = FK 到条款 PK
  3. ETC...

要求:每个组子句只能映射到与自己属于同一类的子句

问题:上表设计并未在数据库级别强制执行该要求。

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

  1. 条款代码
  2. 组条款代码
  3. 班级

其中我可以创建 ClauseCode + Class 作为 FK 到子句表以及 GroupClauseCode + Class 作为 FK 到 GroupClause 表。

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

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

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

4

2 回答 2

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

然后我走得更远,有更多的约束确保类型列与非空 *Value 列匹配

于 2010-09-30T07:02:22.030 回答
0

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

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

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

于 2010-09-30T06:48:44.603 回答