正規化について
第一正規化は、重複した列をなくす為に、行に重複を増やすこと。
第二正規化は、部分関数従属の従属項を分離すること。
第三正規化は、推移的関数従属の従属項を分離すること。
上記の認識で合ってる?
まず結論として、2NF(第二正規化)と3NF(第三正規化)についての説明は概ね正しいものの、1NF(第一正規化)の説明は誤解を招きやすい表現になっていると言えます。
第一正規化 (1NF) について
「重複した列をなくす為に、行に重複を増やすこと」
という表現は、1NF の本質的な要件を正確に言い表しているとは言いがたいです。
1NF の主なポイントは以下のとおりです。
1. 各列が原子的(アトミック)な値を持つ
• “1つのセルに複数の値が入っていないか?”
• “繰り返しグループ(重複する列群)が存在しないか?”
2. テーブルに重複する行がない(行が一意に特定できる)
• 主キーなどで一意に行を識別できるようにする。
したがって、1NF はよく “繰り返し属性(配列や複数値を含む列)を分解して、列を原子化する” などと表現されます。
• 重複した列(いわゆる「繰り返しグループ」)を排除するために、新しいテーブルを分割する、あるいは 行を分割してデータを記録する 場合もあります。
• 「行に重複を増やす」と表現されることもありますが、それは 「重複した列が排除された結果、必要に応じて元々1行にまとまっていた内容を複数行にわける」 という意味合いに近いです。
したがって「重複した列をなくすために行に重複を増やす」というよりは、
• 「繰り返し列や複数の値を含む列を原子化するために、テーブル設計を見直し、必要に応じて行数やテーブルを増やす」
という表現のほうが、1NF の概念として正確に近いでしょう。
第二正規化 (2NF) について
「部分関数従属の従属項を分離すること」
という説明は概ね正しいです。
• 2NF は 主キーが複合キーのとき に、非キー属性(主キー以外の列)が “主キーの一部” にのみ依存(部分関数従属)している場合を排除することが目的です。
• つまり、複合主キーの “一部” のみに依存している列を新たなテーブルに分離し、「非キー属性は主キーの “全体” に対して完全従属する」 形に整理します。
第三正規化 (3NF) について
「推移的関数従属の従属項を分離すること」
という説明も概ね正しいです。
• 3NF は 非キー属性同士で依存関係(推移的関数従属)がある 場合を排除することが目的です。
• 具体的には「非キー属性 A が別の非キー属性 B に依存し、B が主キーに依存している」ようなケース(A → B → 主キー という推移的依存)を分解します。
まとめ
• 1NF(第一正規化): 「列は原子的である」「繰り返しグループを排除する」というのが本質。
• 表現として「行に重複を増やすこと」と言うよりは、繰り返し列や多値列を別テーブルや複数行に分ける ことが多い。
• 2NF(第二正規化): 部分関数従属(複合キーの一部だけへの依存)を排除する。
• 3NF(第三正規化): 推移的関数従属(非キー属性を介した依存)を排除する。
後ろの 2NF と 3NF の説明はほぼその通りで問題ありません。1NF についてはもう少し「繰り返し列の排除」「アトミック化」という観点で捉えていただくと、より正確な理解になります。
“1つのセルに複数の値が入っている”具体例を教えてほしい。
「重複した列(いわゆる「繰り返しグループ」)を排除するために、新しいテーブルを分割する」具体例も教えて。
1つのセルに複数の値が入っている場合や、繰り返しグループを別テーブルに分割する例としては、以下のようなイメージを持つと分かりやすいです。
1つのセルに複数の値が入っている例
例1: 電話番号をカンマ区切りで格納する
問題となるテーブル
PersonID Name PhoneNumbers
1 山田 太郎 090-1111-2222,090-3333-4444
2 佐藤 花子 080-5555-6666
• PhoneNumbers 列に、複数の電話番号をカンマ区切り(またはスペース区切りなど)で入れている例。
• このように「1つのセル」に「複数の値(複数電話番号)」が入っていると、
• 検索や集計(例:電話番号ごとに検索したい)がやりにくい
• 後から「別の電話番号を追加する」場合、データの更新作業が煩雑になる
• 「電話番号の一覧を表示・整形する」のが複雑になる
などの問題が生じます。
1NFに沿った状態への改善案
1NFの考え方(列をアトミックにする)に従い、「1つのセルには1つの電話番号しか入れない」ようにするため、電話番号を別のテーブルに分けたり、行を増やして管理する方法があります。
たとえば Person と Phone という2つのテーブルに分割します。
• Person テーブル
PersonID Name
1 山田 太郎
2 佐藤 花子
• Phone テーブル
PhoneID PersonID PhoneNumber
1 1 090-1111-2222
2 1 090-3333-4444
3 2 080-5555-6666
ここでは
• Person 側に人に関する属性をまとめ
• Phone 側に電話番号を「1レコードにつき1つの電話番号」としてアトミックに扱う
こうすることで
• データ検索が容易になる (「電話番号」で検索するときは Phone テーブルを見る)
• 電話番号を追加するのも簡単 (Phone テーブルに1レコード追加するだけ)
になります。
繰り返しグループ(重複列)を排除する具体例
例2: 同じカテゴリの値を複数の列に持っている
問題となるテーブル
OrderID Product1 Product2 Product3 …
1001 りんご みかん バナナ
1002 ティッシュ - -
上記のように、
• 1回の注文(Order)に複数の商品(Product)が含まれることを想定して、
• Product1, Product2, Product3 … と列をどんどん増やしている
この場合、
• 将来的に Product4, Product5 と増やしたいとき、テーブル定義を修正しなければならない
• 商品数が多い注文ではレコードがスカスカ(NULLやハイフン「-」埋め)になる
• 商品名以外にも “数量” や “金額” などの列を持つ必要が出てきたとき、さらに列が増えて管理が大変になる
など、いわゆる「繰り返しグループ(重複列)」がある状態で、扱いにくいテーブルになってしまいます。
1NFに沿った状態への改善案
繰り返し要素である商品情報を別テーブル (OrderDetails など) に分割します。
• Orders テーブル
OrderID OrderDate CustomerID …
1001 2025-01-08 1
1002 2025-01-09 2
• OrderDetails テーブル
DetailID OrderID Product Quantity Price
1 1001 りんご 5 100
2 1001 みかん 3 120
3 1001 バナナ 2 150
4 1002 ティッシュ 1 300
このように「商品」を別テーブルで行ごとに増やせる形にすることで、
• 商品がいくつ増えても “DetailID, OrderID, Product, Quantity, Price …” を1行増やすだけ
• 「商品」としても柔軟に管理できるし、数量・価格などを含めた集計もしやすい
これが「繰り返し列(重複列)を排除する」具体的な例です。
まとめ
1. 1つのセルに複数の値が入っている
• 例:1つの列(セル)に “090-1111-2222, 090-3333-4444” のように複数の電話番号が入っている場合。
• 原子性を保つために、複数の値を行や別テーブルで分割し、一つのセルには1つの値を格納するようにする。
2. 繰り返しグループ(重複列)を排除する
• 例:注文テーブルに「Product1, Product2, Product3…」のように同じ用途の列がズラッと並んでいる場合。
• これらを別テーブルに分割し、行を増やす構造にすることで、柔軟にデータを管理できる。
どちらも 「1つのセル=1つの値」 や 「重複する列を別テーブルにして行で増やす」 という 1NF の基本思想に基づいた具体例となります。
第一正規形にするためにテーブル分けたら、結果的に部分従属関数の従属項が分けられるから、同時に第二正規化もされたことになる?
結論から言うと、1NF 化(繰り返し列や多値列を排除する)を行ったからといって、必ずしも 2NF(部分関数従属の排除)が自動的に満たされるとは限りません。ただし、1NF の過程でテーブルを分割した結果、偶然にも部分従属が解消されて 2NF も同時に満たすことが「起こり得る」ケースはあります。
1NF と 2NF の違い
1. 1NF (第一正規形)
• 繰り返し属性(重複列)や、1つのセルに複数の値が入っている状態を排除すること。
• 列(セル)を「原子的(1つのセルに1つの値)」に整える。
2. 2NF (第二正規形)
• 主キーが複合キー のときに、非キー属性(主キー以外の属性)が “主キーの一部のみに” 依存している(部分関数従属)状況を排除すること。
• もし主キーが単一列なら、そもそも部分関数従属が発生しないため、自動的に 2NF を満たす。
なぜ 1NF だけでは 2NF が満たされない場合があるのか?
• 1NF は 「同じテーブル内で、重複列を繰り返し持っていないか」「多値を1セルに詰め込んでいないか」 が観点です。
• 2NF は 「複合主キーの一部にのみ依存している属性がないか」 が観点です。
たとえば 複合主キーをもつテーブル で、次のようなケースを考えます。
(PK) ProjectID (PK) EmployeeID EmployeeName ProjectName EmployeeAge …
• 1NF は満たしている(列は原子的・重複列や多値列はない)
• しかし
• EmployeeName や EmployeeAge は本来 EmployeeID にだけ依存する属性
• ProjectName は本来 ProjectID にだけ依存する属性
• この状態では、複合キー (ProjectID, EmployeeID) の一部にしか依存していない もの(EmployeeName など)が同じテーブルに残っているため、部分関数従属が起きて 2NF を満たさない。
もし 1NF 化の段階で「プロジェクトと従業員は別テーブルにしよう」とバラバラに分割してしまえば、結果的に部分従属が解消されて 2NF も同時に満たすかもしれません。しかし 1NF としては「多値を分解する・繰り返し列をなくす」ことが主目的 なので、そこまで踏み込まず 「1つのテーブルに複合キー + それぞれの属性を詰め込んだまま」 の状態で終わる場合も十分ありえます。
まとめ
• 1NF を満たすためのテーブル分割 が、結果として 部分関数従属をも解消し、2NF も同時に満たす ことは「起こり得る」。
• しかし、1NF 化はあくまで「繰り返し列や多値列の排除」が目的 であり、部分関数従属を意識した分割(2NF の目的)までは自動的に行われるとは限らない。
• 特に 複合キーをもつテーブル で、キーの一部にだけ依存する属性が残っていれば 2NF は満たされないため、改めて 2NF を意識した分割を検討する必要がある。
したがって「第一正規形にするためにテーブルを分割した結果、たまたま部分関数従属の問題も解決して 2NF になった」ということはありえますが、「1NF 化すれば自動的に 2NF も満たす」というわけではありません。
第一から第三までの正規化の観点と定義をまとめて。
データベースの正規化には段階があり、基本的には 第一正規形 (1NF) → 第二正規形 (2NF) → 第三正規形 (3NF) の順番で進めていきます。それぞれの観点・定義をまとめると、以下のようになります。
1. 第一正規形 (1NF)
観点
• 繰り返し属性(重複列)の排除
• 1つのセルに複数の値が入っていないか(アトミック性)
定義(要件)
1. すべての列(セル)に、1つの値(原子的な値)が格納されていること
• 例:電話番号をカンマ区切りで格納せず、1つのレコード・カラムには1つの電話番号だけ。
2. 繰り返し列(重複列)が存在しないこと
• 例:Product1, Product2, Product3… という重複列を並べず、テーブル設計で分割する。
1NF を満たしていない例
• 1つのセルに複数の値が入っている
• 例:PhoneNumbers = "090-1234-5678, 090-9999-8888" のように多値を詰め込む。
• 同じ役割の列が繰り返し並んでいる
• 例:Product1, Product2, Product3, ... のように “商品” が横に並ぶ。
2. 第二正規形 (2NF)
観点
• 主キーが複合キーのときに部分関数従属が起きていないか
定義(要件)
1. まず 1NF を満たしていること (前提)
2. 非キー属性は、主キーの “すべての列” に対して完全従属していること
• 主キーが複合キーの場合、その一部にだけ依存する非キー属性(部分関数従属)を持たない。
部分関数従属 … 複合主キー (A,B) のうち、一部 (A) にだけ依存している非キー属性がある状態。
2NF を満たしていない例
(PK) ProjectID (PK) EmployeeID EmployeeName ProjectName
1 101 山田太郎 新規システム開発
1 102 佐藤花子 新規システム開発
• EmployeeName は本来 EmployeeID のみ(ProjectID とは関係なく)依存するのに、同じテーブルに入っている。
• これにより “(ProjectID, EmployeeID)” の一部である “EmployeeID” のみに依存している → 部分関数従属。
解消方法
• Employee テーブルと Project テーブル(またはリレーションテーブル)を分割して、
• EmployeeName 等は EmployeeID を主キーにしたテーブルへ
• ProjectName 等は ProjectID を主キーにしたテーブルへ
と分けることで、部分従属を解消。
3. 第三正規形 (3NF)
観点
• 非キー属性間の依存関係(推移的関数従属)の排除
定義(要件)
1. まず 2NF を満たしていること (前提)
2. 非キー属性同士の間で依存関係(推移的関数従属)がないこと
• 非キー属性 A が別の非キー属性 B に依存し、さらに B が主キーに依存している
• つまり 「A → B → 主キー」 となるような “推移的依存” を排除する。
推移的関数従属 … 主キー 、そして B である場合に、結果的に主キー が成り立つ状態。「非キー属性 B を介して、A が主キーに従属する」関係。
3NF を満たしていない例
(PK) OrderID OrderDate CustomerID CustomerName
1001 2025-01-08 1 山田太郎
• CustomerName は、主キーである OrderID に直接依存しているのではなく、CustomerID に依存している。
• つまり、OrderID → CustomerID → CustomerName という推移的従属が起きている。
解消方法
• Customers テーブルに CustomerID, CustomerName, ... をまとめ、Order テーブルとは CustomerID で関連付ける。
• そうすることで「CustomerID → CustomerName」の関係を切り離す(非キー属性同士の依存を分離する)。
まとめ
1. 第一正規形 (1NF)
• 繰り返し列・多値列を排除 し、列をアトミックにする。
• 「1つのセルに1つの値」「同じような列の繰り返しを作らない」。
2. 第二正規形 (2NF)
• 1NF を満たした上で、複合主キーの一部にだけ依存する非キー属性(部分関数従属)を分離。
• 主キーが単一キーなら、自動的に 2NF は満たす。
3. 第三正規形 (3NF)
• 2NF を満たした上で、非キー属性同士で依存(推移的関数従属)していないかをチェック。
• 非キー属性は、(他の非キー属性を介さず)直接的に主キーへ依存する形にする。
この 1NF → 2NF → 3NF のステップを踏むことで、データの重複や不整合を防ぎ、保守性や拡張性の高いデータベース設計が可能になります。
2NFと3NFの違いがわからない。
あと第四以降はある?
2NF と 3NF の違い
大きくまとめると、以下のように見ると分かりやすいです。
1. 2NF (第二正規形)
• 主キーが複合主キーのとき に起きる「部分関数従属」を排除する。
• 非キー列が「複合主キーの一部」にだけ依存している場合をなくす。
• もし主キーが単一キーなら、そもそも部分従属は発生しないので自動的に 2NF を満たす。
2. 3NF (第三正規形)
• 非キー列同士の“推移的依存” を排除する。
• 「ある非キー列 B に依存していて、B が主キーに依存している」ような間接的な依存(推移的関数従属)をなくす。
• 「非キー列は主キーと直接対応するようにし、ほかの非キー列を介して依存する形を取り除く」イメージ。
具体例でイメージする
2NF が満たされていない例
(PK) ProjectID (PK) EmployeeID ProjectName EmployeeName
1 100 新規開発プロジェクト 山田太郎
1 101 新規開発プロジェクト 佐藤花子
• 主キーが の 複合キー になっている。
• EmployeeName は本来 EmployeeID のみで分かる情報。つまり主キーの「一部 (EmployeeID)」だけに依存している。
• これを「部分関数従属」と言う。
→ 対策: Employee テーブルと Project テーブルを分けるなどして、非キー列が複合キーの一部だけに依存する という状態を解消する。
3NF が満たされていない例
(PK) OrderID OrderDate CustomerID CustomerName
1001 2025-01-08 1 山田太郎
1002 2025-01-09 2 佐藤花子
• CustomerName は、直接 OrderID には依存しておらず、CustomerID に依存している。
• 「OrderID → CustomerID → CustomerName」という 推移的従属 になっている。
→ 対策: Customers テーブルを作って (CustomerID, CustomerName, 住所… など) をひとまとめにし、
Orders
• そうすれば「CustomerID → CustomerName」と分離され、非キー同士の依存が解消される。
第四正規形 (4NF) 以降はあるの?
はい、あります。
• BCNF (Boyce-Codd Normal Form, ボイスコッド正規形)
• 4NF (第四正規形)
• 5NF (第五正規形)
• 6NF (第六正規形)
などが存在し、より厳密にデータの冗長性や依存関係を排除していくための規準として定義されています。
BCNF (ボイスコッド正規形)
• 3NF をさらに厳しくしたもの、と思ってよいです。
• 「すべての関数従属において、決定項(左辺)が候補キーである」ことが条件。
• たとえば、3NF は満たしていても BCNF は満たしていない… というケースがありえます。
4NF (第四正規形)
• 多値従属性 の排除が主な目的。
• 1つのテーブルで複数の多値従属性が混在しているような場合に適用される。
• たとえば「従業員と資格」と「従業員と担当プロジェクト」みたいな 多対多の属性 を同じテーブルに入れているようなときに問題が発生する。
5NF, 6NF
• さらに深いレベルでの分解ルールが示されているが、実務では 3NF または BCNF までで十分なことが多いです。
• 超大規模システムやデータレイクなど特殊な領域・要件では検討されることもあります。
まとめ
1. 2NF と 3NF の違い
• 2NF は 「複合キーの一部にだけ依存している非キー属性(部分関数従属)の排除」。
• 3NF は 「非キー属性同士の依存(推移的関数従属)の排除」。
2. 第四正規形 (4NF) 以降もあるのか?
• はい。BCNF(ボイスコッド正規形)や 4NF、5NF、6NF などがあり、
データの冗長性・不整合をより厳しく排除するための基準として存在する。
• ただし、一般的な業務システムの範囲では 3NF または BCNF までで十分なケースがほとんど。
2NFと3NFの違いは「主キー」の概念がキーポイントになるってこと?2NFは主キーの一部に従属した項があるか、3NFは非キーの一部に従属した項があるか。そうなると主キーってそもそも何?
あとBCNFについてもっと詳しくお願い。
以下、段階を追ってお答えします。
1. 2NF と 3NF の違いは「主キー」の概念がキーポイントになるの?
2NF (第二正規形)
• 「複合キー」(主キーが2つ以上の列で構成される)を持つテーブルの場合にのみ論点になる。
• “主キーの一部にだけ依存している” 非キー属性(部分関数従属) を排除することが目的。
• もし主キーが「単一列」なら、部分関数従属はそもそも起きないので 自動的に 2NF は満たしている。
例
(PK) ProjectID (PK) EmployeeID EmployeeName ProjectName
1 101 山田太郎 新規開発プロジェクト
1 102 佐藤花子 新規開発プロジェクト
• 主キーは (ProjectID, EmployeeID) の複合キー。
• EmployeeName は EmployeeID にだけ依存し、ProjectID とは関係ない。
→ 「複合キーの一部 (EmployeeID) に依存している」= 部分関数従属。
• これが 2NF 違反 になる。
3NF (第三正規形)
• 2NF で部分関数従属を排除したうえで、さらに 「非キー属性同士」の依存(推移的関数従属) を排除する。
• 推移的関数従属 とは、次のような依存関係をいう:
• 主キー → ある非キー列B
• その非キー列B → 別の非キー列A
• 結果的に「主キー → A」の依存が間接的(推移的)に成立している状態。
例
(PK) OrderID OrderDate CustomerID CustomerName
1001 2025-01-08 1 山田太郎
1002 2025-01-09 2 佐藤花子
• 主キーは (OrderID) で「単一キー」なので、2NF の部分従属問題は起きない。
• しかし CustomerName は直接 (OrderID) には依存せず、(CustomerID) に依存している。
• OrderID → CustomerID → CustomerName という形 (推移的従属)。
• これが 3NF 違反 になる。
まとめると
1. 2NF
• 「複合主キー」の一部だけに依存する非キー属性が残っていないか
• → 主キーの概念(複合キーのときに注意) がカギ
2. 3NF
• 非キー属性が、ほかの非キー属性を介して主キーに依存していないか
• → 「非キー属性同士の依存関係」をなくそう
したがって、「2NF と 3NF の違い」においては 主キーは当然重要な概念 ですが、2NF は特に「複合主キー」の場合に意識すべきもの、3NF は「非キー同士の依存」まで視野を広げてチェックする、というイメージです。
2. そもそも主キーって何?
主キー (Primary Key)
• 同じテーブルの中に、主キーの値が重複してはいけない。
• 主キーが 複合主キー になる場合は、複数の列を組み合わせて一意性を保つ。
補足:候補キーと主キー
• 候補キー (Candidate Key) は、テーブルの中で「これだけで行を一意に特定できる」可能性を持つすべてのキー候補のこと。
• その中で、実際にテーブルの主たるキーとして選択したものが「主キー (Primary Key)」となる。
3. BCNF (ボイスコッド正規形) についてもっと詳しく
BCNF (Boyce-Codd Normal Form)
• しばしば「3.5NF」と呼ばれることもありますが、正式には「3NF の発展形 (上位)」です。
BCNF の定義
すべての関数従属 において、 が候補キー (Candidate Key) であること。
• 「関数従属」= 「X の値が決まれば、Y の値が一意に定まる」 という関係。
• BCNF は、3NF が許容していたある種の例外(主キー以外の列が決定項になるケース等)を許さない。
• つまり 「決定項になれるのは候補キーだけ」 という厳格なルール。
3NF を満たすけど BCNF を満たさない例
3NF では「主キー以外の列が左辺になる関数従属」であっても、
• その非キー列が 候補キーでもない かつ 主キーに依存している、
• かつ 非キー列がプライム属性(候補キーの一部)である などの条件で、
「条件を満たしていれば 3NF としては合格」という場合がある。
しかし BCNF はもっと厳しく、
• 「すべて」の関数従属で “決定項” は候補キーでなければならない
• 非キーが左辺に来るような従属は許されない
具体例(やや高度)
• 店舗テーブルとかで、ある「組み合わせ」でしか一意にならないが、その一部分が別の属性を左右するとか、複合的なケースで起こりやすい。
• 代表的なものに「逆関数従属」問題などがある(詳しくは「BCNF 逆関数従属」で調べると出てくる)。
BCNF が必要になる場面
• 通常の業務システムでは、3NF で十分なことがほとんど。
• 「ある非キー列が、別の非キー列を決定する」ような複雑な依存がどうしても発生する テーブル構造の場合、BCNF を適用してテーブル分割しなければ不整合が起きることがある。
• 大規模・複雑な要件のデータモデリングで、BCNF まで厳格に適用するとデータの冗長性をより少なくできるが、実運用でテーブルが増えすぎるなどの弊害もあるためバランスが大事。
まとめ
1. 2NF と 3NF の違い
• 2NF は「複合キーの一部 にだけ依存している非キー属性を切り離そう」
• 3NF は「非キー同士 で依存している(推移的関数従属)項目を切り離そう」
2. 主キーとは
• テーブルのレコードを一意に識別するための列、もしくは 列の組み合わせ。
• 複合キーの場合は「2つ以上の列を組み合わせて主キーになる」。
3. BCNF (ボイスコッド正規形) とは
• 3NF より厳格な正規形。
• 「すべての関数従属において、従属の左辺(決定項)は候補キーであること」 を要求。
• 3NF でOKになるケースでも、BCNF はさらに厳しいルールを課すので、場合によっては追加のテーブル分割が必要になる。
結局、正規化 は「データ冗長をなくし、整合性を保ちやすくする」ための手法ですが、
• 高度な正規形に進むほど、テーブル数・JOIN が増える など運用上のコストも増します。
• 一般的には 3NF(または BCNF) までやれば、業務システムとしては必要十分なことが多いと言われています。
候補キーって何?
候補キー (Candidate Key)
• テーブルの行(レコード)を一意に特定できる 列(もしくは列の組み合わせ)で、
• その列(または列の組み合わせ)から余計な列を取り除いたら “一意性が失われる” という 最小単位 のこと
です。
1. 候補キーのイメージ
• 「これがあればテーブル内のレコードを一意に識別できる!」という候補となるキーです。
• 候補キーが複数あるテーブルもあります(例:社員ID でも一意、メールアドレスでも一意、など)。
例:社員テーブルの場合
社員ID (INT) 社員名 (VARCHAR) メールアドレス (VARCHAR)
1001 山田太郎 yamada@example.com
1002 佐藤花子 sato@example.com
• 社員ID:重複しない
• メールアドレス:一意と仮定すれば重複しない
この場合、
• 「社員ID」 も 「メールアドレス」 も、どちらもレコードを一意に特定できます。
• したがって 「社員ID」 と 「メールアドレス」 はどちらも候補キーになります。
2. 主キー (Primary Key) との違い
• 候補キー は「一意に特定できる可能性を持つすべてのキー」のこと。
• 主キー (Primary Key) は、そのうち 実際に“これをテーブルのメインのキーとして使う” と選ばれたキー。
上記の例では、会社の運用方針などによって「社員ID」を主キーにする場合が多いと思います。
しかしもし「社員ID」がない設計や、「メールアドレス」が必ず重複しないと保証される運用であれば、メールアドレスを主キーに選んでもよい、という話になります。
• 候補キー:社員ID、メールアドレス
• 主キーとして実際に採用したのは「社員ID」、というイメージです。
3. ミニマル性(最小性)とは?
候補キーは「ミニマル性 (minimality)」を満たす
• ミニマル性:もし複数列の組み合わせで一意性を保っていても、その組み合わせの一部を削除すると一意性が保てなくなる場合が候補キー。
• 逆に、その組み合わせから1つ列を除いてもまだ一意性が成り立つようであれば、それはもっと小さな候補キーがあるはずなので「真の候補キーではない」という考え方です。
例:複合候補キー
(PK?) 受注番号 (PK?) 商品コード 個数 単価
1001 A100 10 300
1001 A200 2 500
• (受注番号, 商品コード) の組み合わせで一意になる場合、これら2つが “候補キー” となりうる。
• 「受注番号」単体だけでは重複が起きるし、「商品コード」単体だけでも重複が起きるので、単体では一意性を保てない。
• したがって (受注番号, 商品コード) はミニマルな組み合わせとして、候補キーになり得る。
4. まとめ
1. 候補キー (Candidate Key)
• テーブルの中で行を一意に特定できる すべてのキー(列の組み合わせ)
• かつ その組み合わせを最小限にしても一意性が保たれる(ミニマル性) もの
2. 主キー (Primary Key)
• 多数ある候補キーの中で、実際にテーブルの主たるキーとして選んだもの。
3. 複合キー (Composite Key)
• 複数の列を組み合わせてキーを構成する場合がある。
• それが候補キーにもなるし、採用されれば主キーになる(複合主キー)。
「候補キー」は「主キーになりうる可能性を持ったキー全般のこと」
BCNFと第三正規化って何が違う?
結論
• 3NF (第三正規形) は「非キー属性が 主キーの一部 や ほかの非キー属性 に依存しない」ことを要件とするが、ある種の例外 を許容している。
• BCNF (ボイスコッド正規形) は「すべての関数従属 において、 は候補キー(スーパーキー) でなければならない」という、3NF よりもさらに厳密な要件を課している。
1. 3NF (第三正規形) の定義
3NF では、すべての関数従属 において以下の条件を満たす ようにテーブルを分割します。
1. が 候補キー (スーパーキー) である
• つまり の値が決まればレコードが一意に特定できる。
2. または が「主キーを構成する列」(プライム属性) である
• 候補キーの一部となっている列(プライム属性)なら OK とする。
この “(2) プライム属性なら OK” という 例外規定 があるため、
• 「決定項 がキーではない」 場合でも、
• 「右辺 がプライム属性」であれば 3NF の要件を満たす
という “少しゆるい” 基準になります。
2. BCNF (ボイスコッド正規形) の定義
BCNF では、すべての関数従属 において
• は候補キー (スーパーキー) であること
を 必ず 満たす必要があります。
3NF のように 「右辺がプライム属性なら例外OK」 という規定はありません。
すべての従属において、左辺
3. 3NF と BCNF の違い
1. 3NF はある種の例外 (右辺がプライム属性) を許容する
• したがって、「キーではない列が左辺 (決定項) に来る関数従属」であっても、右辺がプライム属性であれば 3NF を満たす。
2. BCNF はその例外を一切認めず、すべての従属で “左辺はキー (スーパーキー)” を要求する
• そのため、3NF では大丈夫だった関数従属が、BCNF では違反となってしまうケースがある。
例: 3NF は満たすけれど BCNF は満たさない状況
• 複雑な例になりますが、「非キー列が別の非キー列を決定するが、その決定される非キー列が主キーの一部でもある」 というような状況があると、3NF では容認されても BCNF では分解が必要になります。
4. どちらを使うべき?
• 実務レベル では、3NF で十分データの冗長を抑えられることが多く、BCNF にしなければならないケースはそれほど多くありません。
• ただし、学術的・理論的 には「すべての更新異状 (update anomaly) を防ぐため」に BCNF が望ましいとされます。
• BCNF の要件を満たすためにさらにテーブルを分割すると、JOIN が増えすぎたり 実装が複雑になったりするため、バランスが必要です。
まとめ
1. 3NF (第三正規形)
• 「主キーではない列同士の推移的依存 をなくす」ことが大きな目的。
• 左辺がキーでない関数従属 であっても、右辺が「プライム属性(候補キーの一部)」なら 3NF を満たす、といった例外規定がある。
2. BCNF (ボイスコッド正規形)
• 「すべての関数従属において、左辺は候補キー (スーパーキー) でなければならない」という、3NF より厳しい条件。
• 3NF で問題とされないケースでも、BCNF ではさらにテーブル分割が必要になる場合がある。
要するに、3NF は“少しゆるい”、BCNF は“めちゃくちゃ厳しい” と思えばイメージしやすいです。