web-dev-qa-db-ja.com

通常は行を一意に識別しますが、場合によってはnullであるフィールドを使用してテーブルを正規化します

これが以前に尋ねられ、答えられた場合、私を許してください。

私はPostgreSQLで実装される、在庫管理システムのスキーマの概要を説明しています。すべての製品とサービスにはSKUがあります。 ほとんど当社の製品の一部は、個別の「アイテム番号」(それがディストリビューターのカタログ番号、メーカーのモデル番号など)を持つメーカーまたはディストリビューターから来ています。しかし、それらすべてがそのような数を持っているわけではありません。社内で製造する小さなアセンブリがあり、通常、アイテム番号はありません。私たちのサービスにはアイテム番号がありません。これらの理由から、次のCREATE TABLEは私にとって意味があります。

シナリオA:

CREATE TABLE product (
   sku            text PRIMARY KEY,
   name           text UNIQUE NOT NULL, -- alternate key
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
   item_number   text -- hmmm...
);

ただし、これには2つの問題があります。

  1. 時々(たぶん3%から5%の時間)、item_numberは実際にはequalがSKUに与えられます。つまり、私のサプライヤの1つは、特に、製品番号の後に作成された、グローバルに一意なSKUではないと私が疑っている製品を製品に添付しています。

  2. SKUと等しいかどうかにかかわらず、item_number(存在する場合)は、ほとんどすべての場合、私の小さな店舗のドメインで製品を一意に識別するのに十分です。

これを3NFに正規化することが心配です。 item_numberがnullになることがある場合、明らかに代替キーとして宣言できません。しかし、意味的には、私が考えることができるすべての場合において、それは存在する場所での一意の識別子です。それで、すべての属性が非素数属性item_numberに機能的に依存している上記のテーブルは、item_number item_numberが存在する場合は常に、正規化されますか?私はノーだと思っていますが、私は確かに専門家ではありません。私は次のことをすることを考えました:

シナリオB

CREATE TABLE product (
   sku            text PRIMARY KEY REFERENCES product_item_number (sku),
   name           text UNIQUE NOT NULL, -- alternate key
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
);

CREATE TABLE product_item_number (
   sku            text PRIMARY KEY,
   item_number    text
);

機能的な依存関係item_number-> price、item_number->数量などを保存することは実際には要件ではないので、シナリオBはちょっと理にかなっています。プライム以外の属性が他のプライム以外の属性を決定することはありません。

私の最後のアイデアは、item_numberが他に存在しないすべての場合に、単にskuをアイテム番号として使用することでしたが、それが良い方法かどうか疑問に思います。

シナリオC

CREATE TABLE product (
   sku            text PRIMARY KEY,
   name           text UNIQUE NOT NULL, -- alternate key
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
   item_number    text UNIQUE NOT NULL -- alternate key???
);

シナリオCについての私の懸念は、サプライヤーが異なるskuでカタログ番号をリサイクルする場合(たぶん?)、または2つのメーカーが両方とも「d57-red」などを作成する状況があるかもしれないということです。その場合、問題のitem_numbersにプログラムでメーカー名などのプレフィックスを付ける必要があると思います。

もちろん、私はこのすべてを考えすぎているかもしれません。

読んでくれてありがとう。 MDCCLのコメントによると、いくつかの説明があります。

  • SKUは私のドメイン内で常に一意になります(グローバルに一意ではない、サプライヤーが提供する少量のSKUが衝突することはほとんどありません)。
  • Item_numberは、一般向けの属性であり、顧客と、時には私自身が製品を識別するために使用します。たとえば、顧客が私のウェブサイトをスキップして、私にxyz-whiteを持っているかどうか尋ねるように電話するとします。 item_numberはあいまいさを取り除くのに役立ちます。アイテム番号は私の経験では一意です(つまり、私の在庫には反例はありません)が、それ自体はルールではありません。ある日、item_number名前空間の衝突が発生する可能性があります。おそらく、それが起こった場合、私はメーカー名の最初の3文字をitem_numberの前に付けます。
  • item_numbersは常に存在するとは限りません。私はcouldを持たない人に何らかの「代理item_number」を提供すると思いますが、任意のitem_numberは逆効果になります。すぐ上で説明したように、item_numberが存在する場合、それは私と私の顧客が製品を明確にするために存在する必要があります。 item_numberが私が考えたものである場合、彼らは間違った製品を見ていると信じているかもしれません。よく分かりません。
7
Harley

属性item_numberが一意である場合、null値が含まれる可能性がある場合でも、元のテーブルに残すことができます。実際、PostgreSQL manual はこう言っています:

一意の制約上、null値は等しいとは見なされません。

したがって、これは正しい解決策になる可能性があります:

CREATE TABLE product (
   sku            text PRIMARY KEY,
   name           text UNIQUE NOT NULL,
   price          numeric NOT NULL CHECK (price > 0),
   quantity       numeric NOT NULL CHECK (quantity > 0),
   item_number    text UNIQUE
);

ソリューションBよりも効率的であり、ソリューションCよりもプログラミングが簡単です。

このソリューションは正規化されているため、冗長性がなく、挿入/削除の異常もありません。

追加

関係が正式にBoyce Codd正規形(第3正規形よりも厳密)になるためには、各依存関係の行列式が(スーパー)キーである必要があります。ただし、最初に、正規化理論は通常null値を処理しないことに注意してください。たとえば、Elmasri、Navatheの本「Fundamental of Database Systems」を参照。第6版、2010年:

NULL値を含む完全に満足のいくリレーショナル設計理論はまだありません

この場合、少なくとも依存関係があります。

sku → name, price, quantity, item_number

実際、skuは関係のキーです。

次に、null値がないと仮定して、item_numberを一意にしたい場合は、別の依存関係が存在します。

item_number → sku, name, price, quantity

したがって、item_numberは別のキーです。

この関係では、他の機能的な依存関係はなく、これら2つから派生したものの一部であり、これらの依存関係はどちらもBCNFに違反していません(両方の決定要因が鍵です)。したがって、関係はボイス・コッドの正規形になります。

一方、item_numberにnull値が含まれる可能性があると考える場合、2番目の依存関係が保持されていないと見なすことができるため、リレーションシップは再びBCNFにあります。

3
Renzo