【问题标题】:Add constraint to unique row with more than 16 columns将约束添加到超过 16 列的唯一行
【发布时间】:2016-04-28 07:31:59
【问题描述】:

我有几个数据库表,我需要确保某些列始终是唯一的。我目前使用这样的唯一约束:

ALTER TABLE [dbo].[MyTable] 
   ADD CONSTRAINT [AK_MyTable_Unique_Cols] 
   UNIQUE NONCLUSTERED ([Field_1] ASC, [Field_2] ASC,
                        [Field_3] ASC, [FkDeliveryId] ASC)
          WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, 
                ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO

桌子看起来像这样。请注意 Sum 不是约束的一部分。

Field_1 | Field_2 | Field_3 | FkDeliveryId | Sum
Foo     | Foo     | Bar     | 1            | 100
Foo     | Bar     | Bar     | 1            | 900
Bar     | Foo     | Foo     | 1            | 400
Bar     | Foo     | Bar     | 2            | 800 // Not unique 
Foo     | Foo     | Bar     | 2            | 600
Bar     | Foo     | Bar     | 2            | 300 // Not unique

但问题是这些表是通过 C# 动态创建的,有些表的列数会超过 16 列。所以当我试图在一个有 52 列的表上创建约束时,我得到了这个错误:

表 'dbo.MyTable' 上的索引 '' 在键列表中有 52 列。 索引键列列表的最大限制为 16。无法创建 约束或索引。查看以前的错误。

所以现在我正在寻找另一种解决方案。我的 SQL 知识仅限于查询数据库,而不是约束,所以请耐心等待。 :)

我的问题是:如何确保我的表中没有行是重复的(基于选定的列数)?即使超过 16 列?

表可以有不同的列数,列可以是不同的数据类型。

我见过this question 并且喜欢哈希替代方案。但是当我有 50 多列和数百万行时,它会起作用吗?

请问hash always be unique

基于 cmets 的更新:

这些表用于存储导入文件中的数据。我不知道文件的大小或它们有多少列。它是在计划的工作中完成的,因此有关创建表的性能问题并不是很重要。数据必须是持久的,但是实际上只需要约束来确保对于每个插入,没有行应该是重复的。一列理论上可能有varchar(max),这会导致哈希列变得非常大。

【问题讨论】:

  • 这是一个很好的问题。我的第一个想法也是计算列。使用该列或散列列,它将获得相当长的数据长度,这是您必须考虑的事情,以确定您是否可以节省处理所述列的成本。您是否需要每次都在运行中创建这些表,是否有一种方法可以将这些表保存在 SQL 中,即使它只是数据结构?
  • @RichBenner - 感谢您的评论。我已经编辑了我的问题。是的,如果这些表不存在,它们将即时创建。但是一旦创建,它们可以在几年内进行多次插入。

标签: sql sql-server sql-server-2008 constraints


【解决方案1】:

不,哈希并不总是唯一的。发生哈希冲突。

这似乎是一个奇怪的要求。通常可以在表中的列子集上创建键。

解决 16 列限制的通用解决方案是创建一个计算列,该列将所有列与一些不太可能出现在数据中的分隔符连接起来,然后在其上创建一个唯一索引。这与您的链接问题所暗示的基本相同。

但是总体上存在 900 字节的索引键限制。如果您需要支持任意列长度,包括可能超过此长度的 varchar(max),那么您不能使用声明性约束来执行此操作,并且需要一些程序代码。您可以做的最好的事情是在其上创建一个哈希和一个非唯一索引,然后让您的插入过程检查任何哈希重复项以查看它们是否实际上是真正的重复项(可能发生在触发器中以确保始终检查它或 ETL 过程本身 - 这可能会更有效)。

如果您在触发器中执行此操作,则有助于将标识列添加到表中。那么识别重复的代码就是。

SELECT *
FROM Inserted I 
JOIN BaseTable B ON I.HashValue = B.HashValue AND I.Id<> B.Id 
/* check remaining columns to see if actual differences exist in null safe way  
   http://sqlblog.com/blogs/paul_white/archive/2011/06/22/undocumented-query-plans-equality-comparisons.aspx
  */
  AND EXISTS (SELECT B.Col1, B.Col2 
              INTERSECT
              SELECT I.Col1, I.Col2)

如果以上返回任何行,您有违规并可以回滚事务。

【讨论】:

  • 感谢您的反馈。只是为了确保我理解......由于我将有任意列长度,你建议我有一个带有非唯一索引的哈希列并检查触发器中的唯一性吗?
  • @smoksnes 是的,您可以在触发器中执行此操作。虽然这是来自文件,但您是否在 SSIS 中加载?您可以在 SSIS 中计算哈希值,然后对该列进行查找转换,然后进行条件拆分,检查实际列值是否也都相同。
  • 不,我没有使用 SSIS。有一个使用 C# 运行的程序。我想先在业务层(代码)中执行此操作,但认为在 SQL 中执行此操作会更容易、更合适。但现在我不再那么确定了。
  • 我的好先生,这真的很棒。我马上试试。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-04
  • 2013-03-25
  • 1970-01-01
  • 1970-01-01
  • 2011-03-23
相关资源
最近更新 更多