3

我有一个表格来保存用户声明,如下所示(1):

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,类型 = 名称,值 = John

但我不能添加以下声明:

UserAccountID = 1,类型 = 角色,值 = 编辑器

UserAccountID = 1,类型 = 角色,值 = 编辑器

我不能让两行完全相等。所有其他组合都是可能的。

我的想法是使用(2)。它更接近我习惯做的事情......你怎么看?

谢谢你!

4

6 回答 6

3

这一切都取决于你应该是什么主键:) 但很可能 [UserAccountID] 应该是主键,所以第一个解决方案是错误的。它使您能够插入具有相同 [UserAccountID] 的多行(由其他两列不同),这将在与其他表的连接时生成双倍记录。

于 2013-04-29T11:50:52.933 回答
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) 中得到什么?从我所看到的什么都没有。

您绝对可以在选项 (1) 中在 UserAccountID 上创建外键:

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

如果您按 UserAccountID 进行搜索,则两个选项中的集群主键将有效地为您提供结果。

如果要强制执行唯一性,选项 (1) 中的主键和选项 (2) 中的唯一约束/索引都可以完成这项工作。

于 2013-04-29T12:04:47.650 回答
2

第二个更有用,因为您可能会在 WHERE 和 JOIN 中大量使用 UserAccountID,因此在其上建立索引将使您的查询更有效。

于 2013-04-29T11:46:39.087 回答
2

尽管就强制执行的约束而言,PK并且UNIQUE都强制列(或列集)具有唯一值。但从逻辑上讲,primary key它可以让您唯一地标识记录,而不仅仅是维护列上的唯一约束。一个表中只能有一个PK,但可以有多个Unique key。

它更多地是关于使用的上下文:

例如,您有一个表,person (varchar ssn, varchar vehiclenumber, .....)虽然 SSN 和车辆编号是唯一的,但由于该表包含有关此人的信息,因此您希望 SSN 是 PK 并且车辆编号是唯一的。

另一方面,你有一张桌子VehicleInfo (varchar owner_SSN, varchar vehiclenumber, .....)。即使在这种情况下,SSN 和车辆编号也应该是唯一的,但是由于在这种情况下表是车辆,所以在这里您需要将车辆编号PK和 SSN 设为unique

于 2013-04-29T11:49:09.373 回答
1

PK 不能包含NULL值,而UNIQUE可以。在这种情况下,您有NOT NULL字段,但请记住所有一般情况下的这种实质性差异。第二个区别:每个表最多有一个PK(并允许 n 个外键),而您可以根据需要设置任意多个UNIQUE

示例:您的表使用以下字段存储有关(美国卫生系统的)卫生卡的数据:

  • 卡码
  • 用户社会安全号码 (SSN)
  • 用户名/姓

在这种情况下,您的卡代码可能是您系统的 PK,因为您的上下文是卫生系统,但即使不受 PK 约束,您也需要保持唯一的 SSN。实际上,两个字段(SSN 和 Card Code)的 PK 允许不同的 Card Code 使用相同的 SSN,而不同的 SSN 使用相同的 Card Code,而我们需要保持两者的唯一性。通常,我使用一个字段将我在上下文中的记录标识为 PK,而将其他字段标识为 UNIQUE。

因此,如果 UserAccountID 标识了您的记录,您必须将该字段设置为 PK 并将其他字段(VALUE、TYPE)设置为 UNIQUE。提供一个表格示例,我们可以更具体。

于 2013-04-29T12:08:24.387 回答
1

两者都不。我将引入一个新字段,特别是作为主键。我不确定您的业务逻辑,但我认为这三个似是而非的场景都排除了选项 1:

  1. 我们记录了对错误用户的索赔,需要更正!(需要更改 UserAccountID)
  2. 我们记录了错误类型的索赔,需要更正(您需要更改类型)
  3. 索赔的价值已更改(您需要更改价值金额)

这个非常合理的场景排除了选项 2:

  1. 用户提出了第二次索赔。

如果这些数据项中的任何一个可以更改,则意味着它们不适合用作您的 PK。相反,只需添加一个新的自动递增整数字段作为 ClaimID。它占用了更多的空间(一个小的缺点),但好处是您的自然数据值永远不会被作为主键的一部分人为地限制。

另外,我不会在这三个字段上添加唯一性约束;出于类似的原因,您的自然数据值可能不是唯一的。例如,如果用户针对相同的值(可能在不同的日期)提出第二个相同类型的声明。

于 2013-04-29T12:37:17.083 回答