web-dev-qa-db-ja.com

リレーショナルデザイン-1つのテーブル、2つの外部キー、または2つのテーブル、それぞれ1つの外部キー

次のシナリオで、最適設計に関連するいくつかのアドバイスを探します。

  1. Casesテーブルがあります(在庫のケースを表します)
  2. LocationInventoryテーブルがあります(在庫がある場所を表します)
  3. 次に、InventoryNeedテーブル(これは問題の核心)を持っています。これは、ケースと場所を考慮する必要があります。

オプションA:

2つの外部キー列を持つ1つのテーブルで、外部キーの1つだけが入力されます。

表:在庫ニーズ

  1. CaseId(FK)
  2. LocationInventoryId(FK)
  3. 必要な数量

この場合、CaseIdまたはLocationInventoryIdのいずれかがnullになり、もう一方が入力されます。

オプションB:

要約データを取得するために頻繁にUNIONされる必要タイプごとに2つのテーブル。

表:InventoryNeedsCases

  1. CaseId(FK)
  2. 必要な数量

テーブル:InventoryNeedsLocations

  1. LocationInventoryId(FK)
  2. 必要な数量

オプションC:

参照整合性のない1つのテーブル。

表:InventoryNeedsCases

  1. NeedType(ケースまたは場所の値)
  2. NeedId(NeedTypeに基づくCaseまたはLocationInventoryのいずれかの主キーを表します)。
  3. 必要な数量

そして勝者は?データの整合性を確保するために、おそらくAまたはBと絞って絞り込みますが、どちらが最適かはわかりません。あるいは、オプションDがあるかもしれません(共通の列を持つベーステーブルを作成するような...)

更新シナリオ

私がこれを昨夜投稿したとき、私は下流のみを考えていましたが、これらの同じテーブルへの上流の依存関係もあります。私はうまくいけばそれをよりよく説明するかもしれないいくつかの図面を作りました。この出現により、オプションBは関連するテーブルのnbrを爆発させ始めます このSEの回答 ...を読んだ後、私は今よりAに傾いています。

下の写真。次に、赤は在庫ニーズを表し、緑はそれらのニーズを満たす在庫ソースを表します。そして、黄色は目前の問題です...赤と緑を効率的にリンクする方法。

オプションの写真-詳細とコンテキストOption A

オプションB-わかりやすくするためにコンテキストを削除しましたOption B - Inheritance

2
Chad Richardson

ほとんどの場合、私は確かにBをお勧めします。 AとCの両方が、不整合の余地をたくさん残しています。 2つの列の1つだけがNOT NULL(ケースAの場合)であることを強制するのは非常に困難です。一意性が必要な場合は、1つの列が一意の値またはNULLであり、もう1つの列も一意の値またはNULLであり、いずれかがNULLは大変な苦痛です。

Cは、認識したとおり、いくつかの整合性チェックも行いません。

あなたが表現しようとしている情報が何であるか、私は正確に理解していません。しかし、通常、1つのテーブルに2つの異なる他のテーブルの1つへの参照を持たせようとする場合、最初のテーブルの情報は実際には2種類の異なるもので構成されていることに意味があります。

また、次の形式のクエリを多数使用するよりも、UNIONを実行する方がはるかに簡単で読みやすいことを考慮してください。

SELECT *
FROM InventoryNeed
WHERE CaseId IS NOT NULL
AND LocationInventoryId IS NULL

(このクエリ自体はそれほど悪くはありませんが、JOINなどで単一のテーブル名を使用するすべての場所で使用します)。

2
jwg

はい、サブタイプテーブルCasesおよびLocationInventoriesのスーパータイプテーブルを含むオプションDがあります。追加情報については、「スーパータイプ/サブタイプ」パターンおよび「共有主キー」を検索できます。

オプションDが下に移動され、比較のために他のオプションを追加します。


オプションA

Cases
    CaseID   PK  
    ... more columns

LocationInventories
    LocationInventoryID   PK  
    ... more columns

InventoryNeeds
    ?        PK
    CaseID   FK -> Cases (CaseID)
    LocationInventoryID   FK -> LocationInventories (LocationInventoryID)
    NeededQuantity
        CK: CHECK ( CaseId IS NULL AND LocationInventoryID IS NOT NULL
                 OR CaseId IS NOT NULL AND LocationInventoryID IS NULL )

オプションB

Cases
    CaseID   PK  
    ... more columns

LocationInventories
    LocationInventoryID   PK  
    ... more columns

InventoryNeedsCases
    ?        PK
    CaseID   FK -> Cases (CaseID)
    NeededQuantity

InventoryNeedsLocations
    ?        PK
    LocationInventoryID   FK -> LocationInventories (LocationInventoryID)
    NeededQuantity

オプションC

外部キーがないと、参照整合性が失われます。このオプションを採用する理由はわかりません。

Cases
    CaseID   PK  
    ... more columns

LocationInventories
    LocationInventoryID   PK  
    ... more columns

InventoryNeeds
    ?        PK
    NeedType CK: CHECK ( NeedType IN ('C', 'L') )
    NeedID   FK 
    NeededQuantity

オプションD

この1つのテーブルを追加すると、制約が大幅に簡素化されます。複雑になるのは、2つのテーブル(CasesLocationInventories)への行の挿入(および削除)だけです。これには、追加のINSERTが含まれます(またはDELETE from)the BasesNeedsテーブル。

Needs 
    NeedID   PK

Cases
    CaseID   PK  FK -> Needs (NeedID)
    ... more columns

LocationInventories
    LocationInventoryID   PK  FK -> Needs (NeedID)
    ... more columns

InventoryNeeds
    ?        PK
    NeedID   FK -> Needs (NeedID)
    NeededQuantity

オプションE

これは変更された[〜#〜] d [〜#〜]オプションで、参照の整合性を失うことなくCオプションのNeedTypeを組み合わせています。また、オプションDの(偶然かどうかにかかわらず)落とし穴を回避し、NeedCaseの両方にLocationInventoryを挿入できるようにします。

Needs 
    NeedID   PK  UQ1
    NeedType     UQ1  CK: CHECK ( NeedType IN ('C', 'L') )

Cases
    CaseID   PK  FK1 -> Needs (NeedID, NeedType)
    NeedType PK  FK1 
    ... more columns
        CK: CHECK ( NeedType = 'C' )

LocationInventories
    LocationInventoryID   PK  FK1 -> Needs (NeedID, NeedType)
    NeedType              PK  FK1
    ... more columns
        CK: CHECK ( NeedType = 'L' )

InventoryNeeds
    ?        PK
    NeedID   FK1 -> Needs (NeedID, NeedType)
    NeedType FK1
    NeededQuantity
2
ypercubeᵀᴹ