推移的な外部キーを追加する必要がありますか?


11

簡単な例:顧客のテーブルがあります。

create table Customers (
  id integer,
  constraint CustomersPK primary key (id)
)

データベース内の他のすべてのデータはにリンクする必要があるCustomerため、たとえばOrders次のようになります。

create table Orders (
  id integer,
  customer integer,
  constraint OrdersPK primary key (customer, id),
  constraint OrdersFKCustomers foreign key (customer) references Customers (id)
)

次のようにリンクするテーブルがあるとしますOrders

create table Items (
  id integer,
  customer integer,
  order integer,
  constraint ItemsPK primary key (customer, id),
  constraint ItemsFKOrders foreign key (customer, order) references Orders (customer, id)
)

別の外部キーをItemsto に追加する必要がありCustomersますか?

...
constraint ItemsFKCustomers foreign key (customer) references Customers (id)

代わりに画像:破線/ FKを追加する必要がありますか?

簡単な例のスキーマ


編集:テーブルに主キーの定義を追加しました。上記で述べた点について繰り返し述べたいと思います。データベースは、正確性/セキュリティ対策として、基本的に顧客によってサイロ化されています。したがって、すべての主キーにはcustomerID が含まれています。


2
いいえ、すべきではありません。追加のFKは必要ありません。制約は他の2つのFKによって強制されます。
ypercubeᵀᴹ

@ypercube冗長なFKを使用するとパフォーマンスが低下しますか?あなたが考えることができるどんな利点?...
vektor 2014

1
@vektor、パフォーマンスの側面はおそらく1つのRDBMSによって異なりますが、一般に、PK / FKテーブルのいずれかでのすべての挿入/更新/削除は、制約。大きなPKテーブルでは、このパフォーマンスの低下はかなり深刻になる可能性があります。
Daniel Hutmacher、2014

回答:


6

これはオリジナルのアイデアだと思います。

ここに画像の説明を入力してください

最初に注目するのは{CustomerID, CustomerOrderNo, OdrerItemNo}、例では2つだけではなく、LineItemテーブルのPKに3つの属性があることです。

次に注意すべきことはid、属性に総称名を使用したことによる混乱です。

CustomerOrderNo理想的な顧客ごとに(1,2,3 ...)であるべきでOrderItemNo注文ごとに(1,2,3 ...)。

まあ、これは可能であればいいですが、次のように以前の最大値を探すクエリが必要です

select max(CustomerOrderNo)
from Order 
where CustomerID = specific_customer ; 

これは、トランザクション量の多い環境では多くの場合好ましくないため、これらが自動インクリメントに置き換えられ、基本的に同じ目的を果たしているのが一般的です。この自動インクリメットが一意になったことは事実であり、そのため、これをKEYとして使用できますOrderItemNo

だから、いくつかの名前変更CustomerOrderNo -> OrderNoOrderItemNo-> ItemNoあなたはこのモデルに到着するかもしれません

ここに画像の説明を入力してください

だから今、あなたOrderが次を見てみると、ユニークです

{OrderNo}             -- PK
{CustomerID, OrderNo} -- superkey,  AK on the diagram.

がFKとして機能{CustomerID, OrderNo}するようにLineItemに伝播されることに注意してください。

あなたが少し目を細めると、これはあなたの例に近いですが、あなたの例のPKs {ItemNo} and {OrderNo}2つの列PKとは対照的に-だけです。

今問題は、なぜこのようなものに単純化しないのですか?

ここに画像の説明を入力してください

これは問題ありませんがLineItem、PATH DEPENDENCEが導入されます。Customer直接結合することはできません。結合で使用する必要がありますOrder


私は可能な限り最初のケースを好む-あなたはあなたのお気に入りを選ぶ。そして、明らかに、これらの3つのケースでは、直接FKからLineItemtoへのFKは必要ありませんCustomer


周りを検索しましたが、「パスの依存関係」が「2次の推移的関係」と呼ばれるものの広く採用されている用語として使用されていないようです(私の用語もおそらく正しくありません)
Dai

2

これはアイテムの「注文」によって暗示されるため、「アイテム」は「顧客」を直接参照してはなりません。したがって、「items」テーブルの「customer」列はまったく必要ありません。

アイテムと顧客との関係は、既存の外部キーによって保証されます。

orders.idがID列である場合は、items.customerをすべて削除することを検討してください。


1
おかげで、「顧客」も「アイテム」から「注文」までの最初のFKに含まれていることに気付きませんでした。私はそれに応じて私の答えを詳しく説明しました。
Daniel Hutmacher

@DanielHutmacherテーブルの主キーが含まれるように質問を編集しました。これは、編集で言及する奇妙なFKを説明します。
vektor 2014

はい、答えを更新しました。:)
Daniel Hutmacher

customerすべてのテーブルを使用する(つまり、DBをサイロ化する)ことは珍しいアプローチだと思います。それは私の前の作品で見たものにすぎないと告白しなければなりません。それはあなたにとって意味がありますか?そのようなデザインを見たことがありますか?
vektor 2014

それは、データウェアハウス(スタースキーマ)のアプローチのように見えます。結合を排除するために、意図的にデータを非正規化する必要があります。または、注文ID列だけが一意でない場合は、主キーを合成できます。つまり、顧客Aの最初、2番目、3番目の注文、顧客Bの最初、2番目の注文などです。
Daniel Hutmacher、2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.