【问题标题】:Unique row constraint in SQL ServerSQL Server 中的唯一行约束
【发布时间】:2012-02-08 08:14:24
【问题描述】:

我有下表

CREATE TABLE [dbo].[LogFiles_Warehouse](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [timestamp] [datetime] NOT NULL,
    [clientNr] [int] NOT NULL,
    [server] [nvarchar](150) COLLATE Latin1_General_CI_AS NOT NULL,
    [storeNr] [int] NOT NULL,
    [account] [nvarchar](50) COLLATE Latin1_General_CI_AS NOT NULL,
    [software] [nvarchar](300) COLLATE Latin1_General_CI_AS NOT NULL,
 CONSTRAINT [PK_Astoria_LogFiles_Warehouse] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

并且希望避免在我的表中出现重复的行。我想过在整个表上创建一个唯一索引,但是 SQL Manager Studio 告诉我这是不可能的,因为键太大了。

除了索引之外,还有其他方法可以对所有列强制执行唯一行吗?

【问题讨论】:

  • 您想要基于哪些列的唯一行?
  • 肯定有一个身份意味着不会有唯一的行,你说的是其余列的唯一性
  • 你能告诉我们这样的约束有什么好处吗?对于时间戳和 clientNr 等字段,我怀疑您甚至可以得到重复的行。
  • 数据是用户可以导入的日志文件。但是当两个用户导入相同的日志文件时,我想避免数据被插入两次。

标签: sql-server tsql indexing unique


【解决方案1】:

在散列值上创建UNIQUE 索引:

CREATE TABLE [dbo].[LogFiles_Warehouse]
        (
        [id] [int] IDENTITY(1,1) NOT NULL,
        [timestamp] [datetime] NOT NULL,
        [clientNr] [int] NOT NULL,
        [server] [nvarchar](150) COLLATE Latin1_General_CI_AS NOT NULL,
        [storeNr] [int] NOT NULL,
        [account] [nvarchar](50) COLLATE Latin1_General_CI_AS NOT NULL,
        [software] [nvarchar](300) COLLATE Latin1_General_CI_AS NOT NULL,
        serverHash AS CAST(HASHBYTES('MD4', server) AS BINARY(16)),
        accountHash AS CAST(HASHBYTES('MD4', account) AS BINARY(16)),
        softwareHash AS CAST(HASHBYTES('MD4', software) AS BINARY(16))
        )

CREATE UNIQUE INDEX
        UX_LogFilesWarehouse_Server_Account_Software
ON      LogFiles_Warehouse (serverHash, accountHash, softwareHash)

【讨论】:

  • 对整个行进行散列并在该散列上创建索引会更容易吗?
  • @Florian:对谁以及如何“散列整行”更容易? 3 个 16 字节字段的索引对服务器来说不是问题。如果您要连接所有值,那么它可能会导致混淆,例如 server=MSSQLServer,account=20081server=MSSQLServer2008,account=1
  • 好的,有道理。我也可以将其他行添加到索引中吗? (即时间戳、clientnr 和 storenr)那么索引最终会有效地覆盖所有列吗?当然没有 IDENTITY。
  • @Florian:当然。如果它们不是 varchars(如 INTDATE),您可以直接添加它们而不是散列。
【解决方案2】:

在最显着的字段上使用触发器 + 一个较小的非唯一索引来帮助缓解表的问题。

这在很大程度上归结为糟糕的数据库设计。软件、帐户等字段不属于该表的开头(或者如果是帐户,则不是客户编号)。您的表格之所以如此宽泛,是因为您从一开始就违反了数据库设计基础。

另外,为了避免非唯一字段,您必须 NT 在唯一测试中拥有 Id 字段,否则您将永远不会有双打开始。

【讨论】:

  • 这只是一个保存日志文件值的表。 没有字段相互之间具有函数、传递、多值或任何其他依赖关系。当然,这意味着永远不可能有两个相同的行 - 但是,在导入日志文件时,用户可以两次导入相同的日志文件,从而创建两个相同的行。
猜你喜欢
  • 1970-01-01
  • 2013-11-01
  • 2013-01-01
  • 1970-01-01
  • 2011-02-17
  • 1970-01-01
  • 1970-01-01
  • 2011-01-11
  • 1970-01-01
相关资源
最近更新 更多