3NF を表現する 1 つの方法は次のとおりです。
すべての属性は、キー、キー全体、およびキーのみに依存する必要があります。
推移的な依存関係 X->Y->Z はその原則に違反しており、データの冗長性と潜在的な変更の異常につながります。
これを分解してみましょう:
- 定義により、関数依存性 X->Y->Z も推移的であるためには、X<-Y が保持されてはなりません。
- Y がキーの場合、X<-Y が成立するため、Y をキーにすることはできません。(脚注1)
- Y はキーではないため、任意の Y を複数の行で繰り返すことができます。
- Y->Z は、同じ Y を保持するすべての行が同じ Z も保持する必要があることを意味します。(FOOTNOTE2)
- 同じ(Y, Z) タプルを複数の行で繰り返しても、システムには有用な情報が提供されません。冗長です。
つまり、Y はキーではなく、Y->Z であるため、3NF に違反しています。
冗長性は変更の異常につながります (たとえば、同じ Y に「接続された」Z のすべてではなく一部を更新すると、どのコピーが正しいかわからなくなるため、本質的にデータが破損します)。これは通常、元のテーブルを 2 つのテーブルに分割することで解決されます。1 つは {X, Y} を含み、もう 1 つは {Y, Z} を含みます。このようにして、Y を 2 番目のテーブルのキーにすることができ、Z は繰り返されません。
一方、X<-Y が成り立つ場合 (つまり、X->Y->Z が推移的でない場合)、X と Y の両方がキーである単一のテーブルを保持できます。このシナリオでは、Z が不必要に繰り返されることはありません。
(FOOTNOTE1) キーは、リレーション内のすべての属性を機能的に決定する (最小限の) 属性のセットです。理論的根拠: K がキーの場合、K の同じ値を持つ複数の行が存在することはできないため、K の特定の値は常に、他のすべての属性の正確に 1 つの値に関連付けられます (1NF と仮定)。定義上 (FOOTNOTE2 を参照)、「正確に 1 つに関連付けられる」ことは、「機能的な依存関係にある」ことと同じことです。
(FOOTNOTE2)定義により、Y->Z は、各 Y 値が正確に 1 つの Z 値に関連付けられている場合に限ります。
例:
各メッセージに正確に 1 人の作成者がいて、各作成者に正確に 1 つのプライマリ電子メールがあると仮定すると、同じテーブルでメッセージとユーザーを表現しようとすると、電子メールが繰り返されることになります。
MESSAGE USER EMAIL
------- ---- -----
Hello. Jon jon@gmail.com
Hi, how are you? Rob rob@gmail.com
Doing fine, thanks for asking. Jon jon@gmail.com
(実際には、これらはMESSAGE_ID
s になりますが、ここでは単純にしておきましょう。)
では、Jon が自分の電子メール アドレスを「jon2@gmail.com」などに変更するとどうなるでしょうか。Jon の両方の行を更新する必要があります。1つだけ更新すると、次のような状況になります...
MESSAGE USER EMAIL
------- ---- -----
Hello. Jon jon2@gmail.com
Hi, how are you? Rob rob@gmail.com
Doing fine, thanks for asking. Jon jon@gmail.com
...そして、ジョンの電子メールのどれが正しいのか、もはやわかりません。基本的にデータを失いました!
DBMS に両方の更新を強制するために使用できる宣言的な制約がないため、状況は特に悪いです。クライアント コードにはバグがあり、並行環境で発生する可能性のある複雑な相互作用をあまり考慮せずに記述されている可能性があります。
しかし、テーブルを分割すると...
MESSAGE USER
------- ----
Hello. Jon
Hi, how are you? Rob
Doing fine, thanks for asking. Jon
USER EMAIL
---- -----
Jon jon@gmail.com
Rob rob@gmail.com
...Jon の電子メールについて知っているのは 1 行だけなので、あいまいさはありません。
ところで、これはすべてDRY 原則の別の表現と見なすことができます。