2016-04-28 47 views
6

我有几个数据库表,我需要确保某些列在一起总是唯一的。我目前使用这样一个独特的约束:将约束添加到具有多于16列的唯一行中

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列的表创建约束我得到这个错误:

The index '' on table 'dbo.MyTable' has 52 columns in the key list. The maximum limit for index key column list is 16. Could not create constraint or index. See previous errors.

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

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

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

我见过this question和散列替代。但是,如果我有50列和数百万行,它会起作用吗?

请问hash always be unique

更新基于评论:

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

+2

这是一个很好的问题。我的第一个想法也是一个计算列。无论是那个或是一个哈希列,它都会达到相当长的数据长度,这是你必须考虑的问题,你是否可以节省处理该列的成本。你是否需要随时创建这些表,是否没有一种方法可以将它们存储在SQL中,即使它只是数据结构? –

+0

@RichBenner - 感谢您的评论。我编辑了一下我的问题。是的,如果表格不存在,它们将在飞行中创建。但一旦创建,它们可以在几年内进行多次插入。 – smoksnes

回答

5

否散列不总是唯一的。哈希碰撞发生。

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

绕过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) 

如果上述内容返回任何行,则表示您有违规行为并且可以回滚事务。

+0

感谢您的反馈。只是为了确保我明白...因为我会有任意的列长度,所以你建议我有一个非唯一索引的哈希列,并检查触发器中的唯一性吗? – smoksnes

+0

@smoksnes是的,你可以在触发器中做到这一点。虽然这是来自一个文件是你加载SSIS?您可以在SSIS中计算哈希,并在该列上进行查找转换,然后使用条件拆分检查实际列值以查看它们是否全部相同。 –

+0

不,我没有使用SSIS。有一个使用C#运行的程序。我一直在考虑在业务层(代码)中这样做,但认为在SQL中执行此操作会更容易和更合适。但现在我不再那么肯定了。 – smoksnes