次のシナリオで、最適設計に関連するいくつかのアドバイスを探します。
オプションA:
2つの外部キー列を持つ1つのテーブルで、外部キーの1つだけが入力されます。
表:在庫ニーズ
この場合、CaseIdまたはLocationInventoryIdのいずれかがnullになり、もう一方が入力されます。
オプションB:
要約データを取得するために頻繁にUNIONされる必要タイプごとに2つのテーブル。
表:InventoryNeedsCases
テーブル:InventoryNeedsLocations
オプションC:
参照整合性のない1つのテーブル。
表:InventoryNeedsCases
そして勝者は?データの整合性を確保するために、おそらくAまたはBと絞って絞り込みますが、どちらが最適かはわかりません。あるいは、オプションDがあるかもしれません(共通の列を持つベーステーブルを作成するような...)
更新シナリオ
私がこれを昨夜投稿したとき、私は下流のみを考えていましたが、これらの同じテーブルへの上流の依存関係もあります。私はうまくいけばそれをよりよく説明するかもしれないいくつかの図面を作りました。この出現により、オプションBは関連するテーブルのnbrを爆発させ始めます このSEの回答 ...を読んだ後、私は今よりAに傾いています。
下の写真。次に、赤は在庫ニーズを表し、緑はそれらのニーズを満たす在庫ソースを表します。そして、黄色は目前の問題です...赤と緑を効率的にリンクする方法。
ほとんどの場合、私は確かに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などで単一のテーブル名を使用するすべての場所で使用します)。
はい、サブタイプテーブル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つのテーブル(Cases
とLocationInventories
)への行の挿入(および削除)だけです。これには、追加のINSERT
が含まれます(またはDELETE
from)the Bases
Needs
テーブル。
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の(偶然かどうかにかかわらず)落とし穴を回避し、Need
とCase
の両方に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