データモデル設計ガイド

第 3 正規形(3NF)— 推移関数従属を排除する

非キー列同士の推移従属をマスタ分離で断ち切る、実務の標準ライン第 3 正規形。

3NF とは

第 3 正規形(3NF)は、「主キー → 非キー A → 非キー B」のような推移関数従属を排除することを求めます。非キー列が、別の非キー列を経由して主キーに従属している状態を解消します。

実務で「正規化する」と言ったとき、事実上ゴールにされるのが 3NF です。3NF まで達していれば、多くの更新異常は防げます

典型例 — 社員に部署名が直接載っている

典型例 — 社員に部署名が直接載っている diagram

employees (id, name, dept_id, dept_name) で、dept_namedept_id 経由で id に依存しています。つまり id → dept_id → dept_name という推移従属です。

影響: 部署名を変更するとき、該当部署に所属する全社員行を更新しないと矛盾します。部署マスタを切り出して、社員テーブルには dept_id だけを残します。

sql
-- NG (3NF 違反)
CREATE TABLE employees (
  id        INT PRIMARY KEY,
  name      VARCHAR(100) NOT NULL,
  dept_id   INT          NOT NULL,
  dept_name VARCHAR(100) NOT NULL  -- dept_id 経由の推移従属
);

-- OK (3NF)
CREATE TABLE departments (
  id   INT PRIMARY KEY,
  name VARCHAR(100) NOT NULL
);
CREATE TABLE employees (
  id      INT PRIMARY KEY,
  name    VARCHAR(100) NOT NULL,
  dept_id INT          NOT NULL REFERENCES departments(id)
);

「派生列」との見分け方

3NF 違反っぽく見えて、実は計算で導出される列total = price * quantity など)は厳密には「別のマスタに分けるべき事実」ではなく、冗長な派生値です。これは正規化の問題というより「計算結果を保存するか都度計算するか」という非正規化の判断に分類されます。

見分け方: その列は「他テーブルの主キー経由で決まる」ものか、「同じ行の別の列から計算できる」ものか。前者は 3NF 問題、後者は性能判断です。

3NF で止める実務判断

BCNF 以降は候補キーが複数ある複雑なケースに限って必要になります。多くのアプリでは主キーは単一の代理キー(id)で、候補キーが重なることが稀なので、3NF と BCNF は事実上同じ結果になります。

まず 3NF を目標にし、候補キーが複数あるテーブルを見つけたときだけ BCNF を意識する — これが現実的な進め方です。