2009-06-06 8 views
10

SQLでは、列のグループのうちの1つの列に値があり、それ以外の列がNULLであることを強制する方法はありますか?多分制約やトリガーですか?このタイプのものはルックアップテーブルのためのものかもしれませんが、これをより良く実現する代替テーブルデザインはありますか?例えばSQL:列のグループに単一の列のみが設定されているように強制する方法

ID OtherTable1ID OtherTable2ID OtherTable3ID 
----------------------------------------------------- 
1  23    NULL    NULL 
2  NULL    45    NULL 
3  33    55    NULL -- NOT ALLOWED 

主な問題は、これらの列が他のテーブルへのすべてのFKSであるということですので、私は単一の列にそれらを折りたたむことができません。

私はSQL Serverを使用していますが、何らかの回答があります。

+0

更新いただきありがとうございますが、データベース設計の詳細についてお伝えください。たとえば、これはサブタイプの状況ですか?この表は、他の表の1つだけのサブタイプである可能性があります。また、「その他」の列がすべてNULLであることは許可されていますか? –

+0

ルックアップテーブルのように見えます。基本的に、FKをもう1つ追加すると、もう1つの列が追加されますか? –

+0

ええ、それは基本的に私のためのルックアップテーブルです。別のルックアップパラメータを追加する必要がある場合は、別のFK列を追加する必要があります。これを達成するより良い方法はありますか? –

答えて

13

は、3つの列のために[OK]を動作しますが、それはの「直線的に成長している」(代わりに「二次的に成長している」)量を任意の数の列に、より良い一般化するので一般性のために、私は

(cast(col1 is not null, int) + 
cast(col2 is not null, int) + 
cast(col3 is not null, int)) = 1 

を好みます(これはint型のブール型の明示的なキャストを必要としないSQL方言のほうが丁寧ですが、SQL Serverのいずれかであるかどうかはわかりません)。

+4

SQL Serverの場合、これはおそらくもっとうまくいくでしょう... col1 IS NOT NULL、1 else 0 end + case col2 IS NOT NULL、1 else 0 end <2) –

+1

@Glen Little:提供されている構文に同意しますが、OPのケースの比較はまだ '... = 1 'となる。 –

6

以下は動作するはずのような制約:

(column1 is null and column2 is null) 
    or (column1 is null and column3 is null) 
    or (column2 is null and column3 is null) 

しかしこれは、null以外の列が含まれているためにそれを強制しません。これを行うには別の制約を追加:あなたはそれらのもののセットのための一つの列を使用してしたいかのように

column1 is not null 
    or column2 is not null 
    or column3 is not null 
0

をそれは私に聞こえます。おそらく、あなたはそれがFoo,3またはBar,7またはBaz,9であると言うために何らかのタグを使うことができますか? tvanfossonの提案制約@

+0

私は私の質問でこれを明確にする必要がありますが、私が直面している問題は、列が他のテーブルへのFKsです。私の質問を更新しましょう、申し訳ありません –

+0

ああ、今それは面白くなる!これについて少し考えてみましょうが、基本的にRDBMSの実装に問題があるかのように聞こえます。残念ながら、この意味で、私はそこに良いものはないと思っています... –

+0

(明確にするために、列の型を宣言できないようにする必要はありません、またはそれへの参照、または他のものへの参照 "を参照してください)。 –

1
CREATE TABLE Repro.Entity 
(
    entityId INTEGER IDENTITY (1, 1) NOT NULL, 
    column1 INTEGER, 
    column2 INTEGER, 
    column3 INTEGER, 
    CONSTRAINT Entity_PK PRIMARY KEY(entityId), 
    CONSTRAINT Entity_CK CHECK(
     (column1 IS NOT NULL AND column2 IS NULL AND column3 IS NULL) OR 
     (column1 IS NULL AND column2 IS NOT NULL AND column3 IS NULL) OR 
     (column1 IS NULL AND column2 IS NULL AND column3 IS NOT NULL)) 
) 
1

私にとっては、悪い設計のようです。 IDはこの表の主キーであるため、すべての外部キー関係の正当な値になります。つまり、値が許容範囲内にあることを保証するために、フロントエンド/ビジネスレイヤーで余計な作業をする必要があります。

たとえば、テーブルが設定されている方法では、テーブル2は、使用するはずのルックアップ値として1を使用し、データベースはそれをトラップしません。

私はおそらくこのルートに行かないでしょう。単にlookupという名前のスキーマを作成し、ルックアップ値ごとに1つのルックアップテーブルを作成します。このようにして、データベースはすべての制約を適切に実施します。

ルックアップテーブルの設定方法は、現在、整数の外部キーに制限されています。場合によっては、良いアイデアではないかもしれません。たとえば、国コード/コードを表す整数値ではなく、その状態コード/コードを保存したいとします。

+0

私はあまりにもNULL可能な列を避けることを好むが、OPの設計(要求されたように動作する制約に従う)は、正確に1つの非NULL値を強制する制約を書くことができますトリガー(または同様のもの)を使用して独自の '分散外部キー'(Google Hugh Darwen)をロールしない限り、参照テーブルにゼロ行が存在する可能性があります。 – onedaywhen