2016-04-28 8 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の知識は制約にではなく、DBを照会することに限られています。 :)

私のテーブルの行が複製されていないことを確認するにはどうすればよいですか? 16列以上の場合でも?

テーブルの列数が異なり、列のデータ型が異なる可能性があります。

私はthis questionを見たことがあります。しかし、私は50 +列と何百万の行を持っているときに動作しますか?

hash always be uniqueとなりますか?コメントに基づいて

更新:

テーブルがインポートされたファイルからのデータを格納するために使用されています。ファイルのサイズや列の数はわかりません。スケジュールされたジョブで実行されるため、テーブルの作成に関するパフォーマンスの問題はあまり重要ではありません。データは永続的でなければなりませんが、実際には、各挿入に対して行が重複しないようにするために制約が必要です。理論的には、カラムにはvarchar(max)があり、ハッシュカラムが非常に大きくなることがあります。

+2

これは素晴らしい質問です。私の最初の考えは計算カラムでもありました。それか、ハッシュ・カラムのどちらかでかなりのデータ長になるでしょう。これは、あなたが上記のカラムを処理するコストを惜しまないかどうかを検討しなければならないものです。毎回これらのテーブルを作成する必要がありますか?たとえそれがデータ構造であってもSQLでこれらのテーブルを永続化できる方法はありませんか? –

+0

@RichBenner - ありがとうございます。私は少し質問を編集しました。はい、存在しない場合、テーブルはオンザフライで作成されます。しかし、いったん作成されると、数年にわたって複数の挿入が可能になります。 – smoksnes

答えて

5

いいえ、ハッシュは必ずしも一意ではありません。ハッシュ衝突が発生します。

これは奇妙な要件です。通常、キーは表の列のサブセットで作成できます。

16桁の制限を超える一般的な解決策は、すべての列を連結し、データ内では発生しそうな区切り文字で連結し、次にその上に一意のインデックスを作成する計算列を作成することです。基本的にリンクされた質問と同じです。

ただし、全体的に900バイトのインデックスキーの制限があります。 varchar(max)を含む任意の列の長さをサポートする必要がある場合は、これを超える可能性があります。宣言的制約でこれを行うことはできず、手続き型コードが必要になります。あなたができるのは、ハッシュとその上にユニークではないインデックスを作成して、挿入プロセスがハッシュの重複をチェックして、それらが実際に重複しているかどうかを確認することです(常にチェックされるか、ETLプロセスそれ自体はより効率的です)。

トリガーで行うと、ID列をテーブルに追加するのに役立ちます。次に、重複を識別するコードは次のようになります。

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

関連する問題