2013-04-29 109 views
3

我有一個表來保存用戶權利要求如下:(1):PK和唯一約束

CREATE TABLE [dbo].[UserClaims] (
    [UserAccountID] [int] NOT NULL, 
    [Type] [nvarchar](150) NOT NULL, 
    [Value] [nvarchar](150) NOT NULL, 
    CONSTRAINT [PK_dbo.UserClaims] PRIMARY KEY ([UserAccountID], [Type], [Value]) 
) 

我有相同的表(2)第二個選項:

CREATE TABLE [dbo].[UserClaims] (
    [UserAccountID] [int] NOT NULL, 
    CONSTRAINT PK_UserClaims_UserAccountId PRIMARY KEY CLUSTERED (UserAccountId), 
    [Type] [nvarchar](150) NOT NULL, 
    [Value] [nvarchar](150) NOT NULL, 
    CONSTRAINT UQ_UserClaims_Value_Type_UserAccountID unique (Value, [Type], UserAccountID) 
) 

而我有這個表格:

CREATE TABLE [dbo].[UsersAccounts] (
    [UserAccountID] [int] IDENTITY NOT NULL, 
    CONSTRAINT PK_UsersAccounts_UserAccountId PRIMARY KEY CLUSTERED (UserAccountId) 
) 

當我得到一個用戶時,我總是需要從UserClaims獲得所有的聲明。

的UserAccountID足以識別所有用戶要求...

在選項(2)的UserAccountID既是PK和FK。

我需要能夠以下行添加到UserClaims:

UserAccountID = 2,類型=角色,值=編輯

UserAccountID = 1,類型=角色,值=編輯

UserAccountID = 1,類型=角色,值=會員

UserAccountID = 1,類型=名稱,值=約翰

但我不能添加FOL降脂索賠:

UserAccountID = 1,類型=角色,值=編輯

UserAccountID = 1,類型=角色,值=編輯

我不能有兩排完全地相等。所有其他組合都是可能的。

我的想法是使用(2)。這與我以前做的事更接近......你怎麼看?

謝謝!

+0

在這種情況下,UserClaims UserAccountID與作爲身份的Users表UserAccountID相同。所以當我得到一個用戶時,我也需要得到它的聲明。我永遠不會得到一個索賠本身。這就是爲什麼我使用UserAccountId ...所以我需要索引它使它成爲一個PK?或者唯一約束就足夠了? – 2013-04-29 11:47:19

+0

@twoleggedhorse:恕我直言,你在這裏混淆理論和實現約束是一個**抽象的**數據模型概念,*可以*實現/強制執行索引(這是一個具體的*物理*事物)(它似乎是MS和mysql文檔也將它們混合起來) – wildplasser 2013-04-29 12:02:15

回答

2

第二個更有用,因爲您可能會在WHERE和JOIN中使用UserAccountID很多,所以它上的索引將使您的查詢更有效率。

+1

但是這兩個約束不會做同樣的事情。 – 2013-04-29 11:52:45

+0

是的,我知道這一點。 – 2013-04-29 11:55:18

+0

第一個也適合在WHERE和JOINS中使用UserAccountID,因爲它是一個以UserAccountID開頭的聚集索引。 – 2013-04-29 12:10:51

2

儘管根據強制約束條件,PKUNIQUE都強制列(或列集)具有唯一值。但從邏輯上講,primary key是讓您唯一識別記錄的方法,而不僅僅是維護列上的唯一約束。表中只能有一個PK,但可以是多個唯一鍵。

它更多使用的範圍內:

例如,您有一個表person (varchar ssn, varchar vehiclenumber, .....)雖然SSN和車輛數量都意味着是唯一的,但由於該表有關於這個人的信息,你會希望SSN是PK和車輛號碼是唯一的。

另一方面,你有一個表VehicleInfo (varchar owner_SSN, varchar vehiclenumber, .....)。即使在這種情況下,SSN和車輛號碼也是獨一無二的,但是因爲在這種情況下表格是車輛,所以在這裏您需要車輛號碼爲PK和SSN爲unique

+0

通常,我喜歡每個表總是有一個PK ...然後使用約束。我比(1)更接近使用選項(2)。我只是用更多的信息更新了我的代碼。 – 2013-04-29 12:42:24

3

這一切都取決於應該做什麼是你的主鍵:) 但很可能[UserAccountID]應該是主鍵,所以第一個解決方案是錯誤的。它使您能夠插入具有相同[UserAccountID](與其他兩列不同)的多行,這將在與其他表的連接上生成加倍的記錄。

+1

這是怎麼回事?爲什麼用戶不能擁有多重索賠? – 2013-04-29 12:08:46

+1

哦,我錯過了桌子的名字。在這種情況下,兩種方法都是錯誤的。其次意味着用戶只能有一個聲明,並且首先聲明用戶只能擁有一個相同類型和金額的聲明,我想在任何業務中whis都是無效的。 所以你實際上並不需要一個表上的唯一/ PK約束,我猜(除非你的業務邏輯陳述了其他的東西 - 那會是什麼原因?)。 我只會在[UserAccountId]上添加一個索引以加快查詢速度,也許[ClaimId]具有主鍵的int identity(1,1)。 – 2013-04-29 12:14:51

+0

用戶只能擁有一個具有相同類型和值的聲明。用戶只能通過值編輯器獲得角色類型的聲明。是否有意義?所以這就是爲什麼我有3列的唯一約束。我剛更新了我的問題以提供更多信息。 – 2013-04-29 12:40:09

2

基礎上只有兩個選擇,我會去的第一個,因爲它拍攝的所有設計要求:

  • 強制唯一性。
  • 表現。

第二個表格的設計也有效,但是以維護兩個索引的額外開銷爲代價。

作爲另一種選擇,我真的進一步規範化UserClaims表具有以下結構:

create table dbo.UserAccount 
(
    UserAccountID int not null primary key 
) 

create table dbo.Claim 
(
    ClaimID  int    not null primary key 
    , Type  nvarchar(150) not null 
    , Value  nvarchar(150) not null 
    , unique 
    (
     Type, Value 
    ) 
) 

create table dbo.UserClaims 
(
    UserAccountID int not null 
    , ClaimID  int not null 
    , primary key 
    (
     UserAccountID 
     , ClaimID 
    ) 
) 

更新 - 爲了更具體地回答你的問題,你可能會想,如果你必須使用第二個需要搜索給定值的所有用戶聲明。

例如,向我展示所有要求超過200,000美元的用戶。如您所見,表格設計實際上取決於您的數據模型以及您問的是什麼類型的業務問題。

更新 - 鑑於提供的額外信息,它現在更清楚你想問什麼。這是我修改回答你的問題的嘗試。

它基本上歸結爲你從選項(2)中得到什麼,你沒有從選項(1)中獲得?沒有什麼我能看到的。

你絕對可以創建UserAccountID的選項(1)外鍵:

alter table dbo.UserClaims 
add constraint fk_UserClaims_UsersAccounts foreign key 
(
    UserAccountID 
) 
references UsersAccounts 
(
    UserAccountID 
) 

如果你被UserAccountID搜索,在這兩個選項聚集主鍵會有效地得到您的結果。

如果要執行唯一性,選項(1)中的主鍵和選項(2)中的唯一約束/索引都會執行該作業。

+0

你好,正常化索賠將是一個好主意,但在這種情況下是不可能的......我不會有辦法正常化它。 – 2013-04-29 12:33:27

1

PK不能包含NULL值,而UNIQUE可以。在這種情況下,您有NOT NULL字段,但請記住所有常規情況下的實質性差異。 第二個區別:每個表最多隻有一個PK(並且允許n個外鍵),而您可以根據需要設置多個UNIQUE

示例: 您的表格存儲有關Sanitary Card(美國的數據)的數據。衛生系統)使用這些字段:

  • 卡代碼
  • 用戶的社會安全號碼(SSN)
  • 用戶名/姓

在這種情況下,您的卡代碼可能的PK你的系統,因爲你的上下文是衛生系統,但你也需要保留唯一的SSN,即使不在PK約束中。實際上,兩個字段(SSN和卡代碼)的PK允許針對不同的卡代碼使用相同的SSN,並且針對不同的SSN使用相同的卡代碼,而我們需要保持唯一。 通常,我使用一個字段來標識我的記錄在上下文中爲PK,其他爲UNIQUE。

因此,如果UserAccountID標識您的記錄,則必須將該字段設置爲PK,將其他(VALUE,TYPE)設置爲UNIQUE。提供一個表格例子,我們可以更具體。

1

都沒有。我會介紹一個新的領域,特別是成爲主要關鍵。我不確定你的商業邏輯,但我認爲這三種可能的情況都排除了選項1:

  1. 我們記錄了對錯誤用戶的索賠,並且需要糾正它! (需要改變UserAccountID)
  2. 我們記錄了錯誤類型的要求,並且需要糾正它(你需要改變的類型)
  3. 索賠的價值已經改變(你需要更改值量)

而這很可能的情形排除選項2:

  1. 用戶已經把第二個索賠。

如果這些數據項可以改變任何,永遠,這意味着他們不適合作爲你的PK使用。相反,只需添加一個新的自動遞增整數字段作爲ClaimID。它需要佔用更多的空間(一個小缺點),但好處是你的自然數據值不會被主鍵的一部分人爲地限制。

此外,我不會在這三個字段上添加唯一性約束;由於類似的原因,你的自然數據值可能不是唯一的。例如,如果用戶放入第二個相同類型的索賠,可能是相同的值(也許在不同的日期)。