第 3 正規形(3NF)— 推移関数従属を排除する
非キー列同士の推移従属をマスタ分離で断ち切る、実務の標準ライン第 3 正規形。
3NF とは
第 3 正規形(3NF)は、「主キー → 非キー A → 非キー B」のような推移関数従属を排除することを求めます。非キー列が、別の非キー列を経由して主キーに従属している状態を解消します。
実務で「正規化する」と言ったとき、事実上ゴールにされるのが 3NF です。3NF まで達していれば、多くの更新異常は防げます。
典型例 — 社員に部署名が直接載っている
employees (id, name, dept_id, dept_name) で、dept_name は dept_id 経由で id に依存しています。つまり id → dept_id → dept_name という推移従属です。
影響: 部署名を変更するとき、該当部署に所属する全社員行を更新しないと矛盾します。部署マスタを切り出して、社員テーブルには dept_id だけを残します。
-- 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 を意識する — これが現実的な進め方です。
