2016-04-28 46 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