関数従属性 (Functional Dependency)
関数従属性とは、リレーション上で属性集合 X の値が定まれば属性集合 Y の値が一意に定まる関係 (X → Y と表記) であり、テーブルの意味的整合性と正規化判定の基準として用いられる概念である。
「A が決まれば B も決まる」= 関数従属
「社員ID が分かれば、その人の氏名は 1 つに決まる」— これは当たり前に感じる関係だが、 正規化の議論では大事なので名前が付いている。関数従属 (functional dependency, FD) だ。 矢印で書くと 社員ID → 氏名。矢印の左が「決める側」、右が「決まる側」。
「決まる」というのは、あるテーブルのどの行を見ても「社員ID が同じなら氏名も同じ」 が成り立つ、という意味。 たまたま同じだった、ではなく、業務ルールとして「社員ID が同じなら氏名も同じはず」と言えるものだけを関数従属として扱う (1 件でも例外が出れば関数従属とは呼ばない)。
| 社員IDPK | 氏名 | 入社日 | 部署ID | 部署名 |
|---|---|---|---|---|
| … | … | … | … | … |
- 社員ID氏名完全関数従属
- 社員ID入社日完全関数従属
- 社員ID部署ID完全関数従属
- 部署ID部署名完全関数従属
- 社員ID部署名推移関数従属部署ID を経由して成立
社員ID → 部署名 も一見成り立っているが、実は「社員ID → 部署ID → 部署名」を経由して間接的に決まっているだけ。この「経由あり」の関数従属を「推移関数従属」と呼び、後で第3正規形が排除の対象にする。
3 種類の関数従属 (これから何度も出てくる)
関数従属には 3 種類あり、それぞれが 2NF・3NF が扱うテーマに対応している。 今は名前と雰囲気だけ覚えておけば OK。実例は各正規形のページで詳しく見る。
- 完全関数従属: 「A と B が両方揃って初めて C が決まる」タイプ。 例:
(注文ID, 商品ID) → 数量。注文ID だけ、商品ID だけでは数量は決まらない。 これは正常な関数従属で、排除の対象ではない。 - 部分関数従属: 「(A, B) の一部分 (例えば B だけ) で決まってしまう」タイプ。 例:
(注文ID, 商品ID) → 商品名は実は商品ID → 商品名だけで成り立つので、注文ID は不要。 これがあると同じ商品名が何度も繰り返されるので、第2正規形 で切り出す対象になる。 - 推移関数従属: 「A → B → C と経由してしまう」タイプ。 例:
社員ID → 部署ID → 部署名。社員ID から部署名を「直接」決めているのではなく、部署ID を経由している。 これがあると同じ部署名が何度も繰り返されるので、第3正規形 で切り出す対象になる。
なぜこの概念が正規化の判定基準になるのか
「同じ情報を 1 か所に書く」を判定するとき、関数従属で見るのが一番シンプル。 例えば 部署ID → 部署名 という関数従属があるということは、 「部署ID が同じ行は部署名も必ず同じ」= 部署名が繰り返し書かれている、ということ。 つまり関数従属を見つけると、そのまま「重複している情報の場所」も見つけたことになる。
正規化 (1NF → 2NF → 3NF) は、こうした「重複を生む関数従属」を段階的に切り出していく手順として理解できる。 各正規形が「どのタイプの関数従属を排除するのか」を意識すると、全体の流れがすっきり見えてくる。
先に「キーの階層」を押さえておこう
関数従属の話を正確にするには キーの階層(スーパーキー・候補キー・主キー) の理解が前提になる。 「主キー全体で決まる」のか「主キーの一部で決まってしまう」のかが、2NF・3NF の判定を分けるからだ。
推移的関数従属を掘り下げる
推移的関数従属 (transitive functional dependency) は、X → Y → Z のように「主キー X から直接 Z が決まっているのではなく、 非キー属性 Y を経由して間接的に決まっている」関係を指す。 「推移関数従属」「推移従属」とも呼ばれる。
典型例が 社員ID → 部署ID → 部署名。 社員ID (主キー) から部署名を決めているように見えるが、実際は「社員ID がまず部署ID を決め、 その部署ID が部署名を決めている」構造だ。ここで問題になるのは次の 3 点。
- 更新異常: ある部署の名前を変えたい時、社員テーブルの全社員行を UPDATE することになる。 1 行でも漏らすと同じ部署ID が別の部署名を持つ矛盾状態が生まれる。
- 挿入異常: 「社員がまだ 1 人もいない部署」を登録できない。 社員行がないと部署名を記録する場所がないからだ。
- 削除異常: その部署に所属する最後の社員行を削除すると、部署の存在情報ごと消滅する。
推移的関数従属を切り出し (別テーブル化) すれば、この 3 種の異常はすべて消える。 これが 3NF がやっていることの本質だ。
多値従属 — 関数従属の「1 対多」版
多値従属 (multi-valued dependency, MVD) は、X ↠ Y と書く。関数従属 X → Y が「X が決まれば Y が 1 つに決まる」なら、 多値従属は「X が決まれば Y の 集合 が決まり、 しかも同じ行にある他の列 (Z) と Y は独立している」関係を指す。 矢印を「二重矢印 ↠」で区別するのが慣例。
典型例: 社員テーブルに「保有スキル」「担当プロジェクト」の 2 列を並べてしまったケース。 1 人の社員が「Go, TypeScript」の 2 スキルを持ち、「A案件, B案件」の 2 プロジェクトを担当しているとする。 両方を 1 テーブルに素直に並べると (社員, スキル, プロジェクト) の組み合わせで 4 行になる (2 × 2 の直積)。だがスキルとプロジェクトの間に本来関係はない — これが「独立した繰り返し」で、 多値従属が現れているサイン。
多値従属を排除するのが第 4 正規形 (4NF)。関数従属だけで判定する 3NF/BCNF では、 この「独立した 1 対多の並列」までは検知できない。正規化の目的(重複を作らず更新異常を防ぐ) を突き詰めると、いずれ 4NF まで登る必要があるが、 実務では 3NF まで到達していれば大半の異常は消える。
関数従属を洗い出す手順
設計段階で関数従属を漏れなく列挙するのが正規化の入り口。手順は以下の通り。
- 属性を列挙する: 対象テーブルに載る全カラムを書き出す (社員ID, 氏名, 入社日, 部署ID, 部署名, …)。
- 候補キーを特定する: 「この列 (または列の組) が決まれば他の全ての列が一意に決まる」 最小の組を挙げる。キーの階層 を参照。
- 候補キー → 非キー属性の関数従属を書く: これは定義上必ず成立する。 例:
社員ID → 氏名、社員ID → 入社日。 - 非キー属性同士の関数従属を業務ルールから拾う: ここが実務の要点。 「部署ID が決まれば部署名も決まる」など、業務上絶対に成立する規則を洗い出す。 サンプルデータで「たまたま同じ」に見えるだけの関係は入れない (反例が出た瞬間に崩れる)。
- 部分関数従属・推移関数従属を分類する: 挙げた FD のうち、 「複合キーの一部だけで成立するもの (部分)」「経由が入っているもの (推移)」を色分けする。 これが 2NF / 3NF で切り出す対象になる。
コツは「サンプルデータではなく業務ルールから導く」こと。 「今のデータでは重複していない」は関数従属の証拠にならない。 「業務上、絶対に重複しない (してはいけない)」という制約が根拠になる。
関数従属と 2NF / 3NF の対応関係
どの正規形がどのタイプの関数従属を排除するのか、対応表で整理しておく。
- 1NF: そもそも関数従属を議論できる形にする段階。 1 セル 1 値・繰り返しグループなしにする。関数従属の分類には踏み込まない。
- 2NF: 部分関数従属を排除。 複合主キーの一部で決まってしまう非キー属性を別テーブルに切り出す。 単一列の主キーなら 1NF を満たした時点で自動的に 2NF になる。
- 3NF: 推移関数従属を排除。 「主キー → 非キー属性 → 別の非キー属性」の経由を、非キー属性を新テーブルの主キーとして独立させることで消す。
- BCNF: 3NF の抜け穴 (候補キーが複数あり、そのうち一部が別の候補キーの一部に対して従属する) を塞ぐ。実務では 3NF と BCNF の差が問題になるケースは少ない。
- 4NF: 多値従属を排除。関数従属では拾えない「独立した繰り返し」を分解する。
つまり正規化とは、テーブル内に潜む関数従属を「無害なもの (候補キー → 非キー)」 と「有害なもの (部分・推移・多値)」に分類し、有害なものを別テーブルに追い出す作業だ。
よくある疑問
関連トピック
- 基礎なぜ正規化が必要か
正規化されていないテーブルでは、同じ事実を複数の行に重複して持つために、挿入・更新・削除の各操作で矛盾や情報損失が発生する。この「更新時異常」を体系的に排除するのが正規化の目的である。
- 基礎キーの階層
正規化の議論に入る前に、スーパーキー・候補キー・主キーの3階層と、外部キー・代替キー・複合キーとの関係を整理する。2NF/3NF の「非キー属性」「部分従属」を語るための語彙を揃える。
- 基礎第1正規形
全ての属性がアトミック値をとり、繰り返しグループを含まない状態が第1正規形。非1NF (unnormalized form) の代表例を並置し、1NF に変換する具体的手続きを図解する。
もっと学びたい方へ(おすすめ書籍)
テーブル設計と正規化、パフォーマンス考慮のインデックス設計まで実務レベルで学べる定番書。第2版ではクラウド対応も強化。
IPAデータベーススペシャリスト試験の総合対策書。インデックス関連は本サイトと合わせて学ぶと理解が深まる。
リレーショナルモデルの理論から、インデックス設計を含む実務で使えるSQLまで解説。
ER 図をどう「使える設計」に落とすか、実務の判断まで踏み込んだ入門書。エンティティの切り出しから多対多の扱いまで具体例が豊富。
ドリル 256 問を実際に打ちながら進める SQL の入門書。付属のブラウザ環境で演習できるので、SELECT から結合・集約までを環境構築で止まらずに通せる。
SQLの本質的な使い方と、インデックスが効くクエリの書き方を学べる。ウィンドウ関数など現代SQLも網羅。
実務でやりがちなSQL・DB設計のアンチパターンとその回避策を体系的に学べる。
PostgreSQLの内部構造・ストレージ・インデックス機構を丁寧に解説。設計と運用計画の鉄則が学べる。
「なぜこの書き方が速いのか」を実行計画から説明する一冊。条件分岐・集約・結合・更新のそれぞれで、良い書き方と悪い書き方を対比しながら読める。
本セクションはAmazonアソシエイトのリンクを含みます。
もっと深くDBを学びたい方へ。
たいてっくが、SQL・データベース設計・パフォーマンスチューニング・IPAデータベーススペシャリスト対策まで、1対1で学習をサポートします。まずは無料相談から。
「教え方も上手で、お人柄も良いメンターです。DB周りの知識はもちろん、何より、しっかり教えてあげようという姿勢がとてもありがたかったです。データベース、SQLの学習を考えている方にはおススメです。」
— H 様(DB・SQL コース受講)「体系的に知識を教えてくださり、実際の業務でも大変役立っております。特に短い時間で効率よく知識の習得や、練習をできているのは期待以上でした。」
— M 様(DB・SQL コース受講)「大変充実したコンテンツでわかりやすいご説明をありがとうございました。基本的な質問にも丁寧にご説明いただき、また業務のご相談にも乗って頂き大変有意義な時間でした。」
— K 様(DB・SQL コース受講)