2010-09-30 57 views
0

我的表架構是這樣數據庫設計 - 如何加強對錶的外鍵約束與代理鍵

1.主表:第

  1. ClauseID = surrogate pk(identity)
  2. ClauseCode = nvarchar用戶指定值
  3. 類= nvarchar的FK到主類表
  4. 等...
此表

ClauseCode +類=候選鍵

2.主表:GroupClause

  1. GroupClauseID =替代PK(同一性)
  2. GroupClauseCode = nvarchar的用戶指定的值
  3. 類= nvarchar的FK到主類表 等...

GroupClauseCode +類=此候選鍵表

3.交易/映射表:: GroupClause_Clause_Mapping:該表將每個組子句多個單獨子句

  1. GroupClauseID = FK到GroupClause PK
  2. ClauseID = FK到第PK
  3. 等...

要求:每個組子句只是能被映射到屬於與它自己相同的類的子句

問題:此上表設計並未在數據庫層面強制執行該要求。

的一種可能的解決方案:表* GroupClause_Clause_Mapping *具有列

  1. ClauseCode
  2. GroupClauseCode

其中i可以創建ClauseCode +類如FK條款表作爲以及GroupClauseCode + Class作爲FK到GroupClause表。

但是,如果我這樣做,那麼代理身份密鑰是無用的,我不如擺脫他們

使用代理鍵的設計有問題嗎?

任何關於如何使用代理鍵仍然強制執行數據庫級約束的建議?

回答

1

如果代碼本身很大/笨重,那麼您可能仍然希望在可用的情況下使用代理。

既然你只需要執行類匹配,那麼你的映射表可以

ClauseID, 
GroupClauseID, 
Class (or possibly ClassID) 

爲了您的主表,你仍然有PK(ClauseID)和唯一約束(ClauseID,類)。然後,您可以決定是否僅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 

然後我走的更遠,並有更多的約束確保類型列非空*值匹配列

+0

砰!將一個唯一的約束(ClauseID,Class)放在主表子句本身上,這樣我就可以從事務表FK中使用它!我腦後只有一個小小的聲音,說這似乎有點誤導,因爲這個獨特約束的類部分實際上是多餘的 - 你會這麼說嗎? – InSane 2010-09-30 07:21:11

+0

@In Sane - 這在某種程度上是多餘的。它只是一個超級密鑰,涵蓋的列數超過了唯一標識一行所必需的數量。但它可以讓你表達更多的完整性規則,這絕對不是多餘的。 – 2010-09-30 07:34:52

+0

是的,你是絕對正確的!我將繼續與您提出的完全一致!謝謝! – InSane 2010-09-30 11:23:16

0

「如果我這樣做,那麼代理身份密鑰是無用的,我可能會擺脫它們。」

這是正確的。這是使用自然鍵而不是代理項的原因之一:當您需要使用自然鍵值實現一些額外的約束或邏輯時。

您可能想引用其他表中的代理項,這樣代理鍵仍然可能有用。如果你根本不使用代理,那麼最好放棄它。代理鍵通常意味着一定的開銷,因爲它們通常被編入索引,這會損害插入的性能。

+0

謝謝!我在這裏看到你的觀點。替代品的原因是,我可以在數字字段而不是字符串上進行聯合/搜索等 - 用戶定義的代碼本質上是文本性的,我希望避免在我的查詢中使用它們。基於你的建議,我想我將不得不選擇一個或其他..這就是我希望它不會來:-) – InSane 2010-09-30 06:58:31

+0

除非字符鍵非常寬,它們不會比int或數字鍵慢。 – PerformanceDBA 2010-10-30 03:47:09