· theory · 8 min read
データベース正規化とは?第1〜第3正規形の変換手順を図解で理解する
なぜデータベースを正規化するのか——冗長性の排除・更新異常の防止という目的から、第1・第2・第3正規形の変換手順まで、応用情報技術者試験・DBスペシャリスト試験の頻出概念を体系化する。

設計が甘いテーブルに起きる問題は3種類ある。
- 挿入異常:新しいデータを入れようとすると不整合が起きる
- 更新異常:1か所を変更すると複数行の修正が必要になる
- 削除異常:1件消すと他の必要なデータまで消えてしまう
これらをまとめて「更新異常」と呼ぶ。正規化とは、更新異常を防ぐためにテーブルを分解・整理するプロセスだ。
正規化前のテーブルで何が起きるか
以下の「受注テーブル」を例に考える。
| 受注番号 | 顧客番号 | 顧客名 | 商品番号 | 商品名 | 数量 | 単価 |
|---|---|---|---|---|---|---|
| 1001 | C01 | 田中商店 | P01 | ノート | 10 | 100 |
| 1001 | C01 | 田中商店 | P02 | ペン | 5 | 200 |
| 1002 | C02 | 佐藤書店 | P01 | ノート | 3 | 100 |
このテーブルには問題がある。
「ノートの単価を100円から120円に変更」したい場合、単価が書かれているすべての行を更新しなければならない。 更新漏れが生じると「同じ商品なのに単価が違う」という矛盾が発生する。これが更新異常だ。
第1正規形(1NF)— 繰り返しグループを排除する
第1正規形の条件:各列が単一値を持つこと(繰り返しグループを持たないこと)
正規化前のテーブルにこんな設計があるとする。
| 受注番号 | 顧客名 | 商品(複数) |
|---|---|---|
| 1001 | 田中商店 | ノート,ペン,鉛筆 |
「商品(複数)」の列にカンマ区切りで複数値が入っているのは1NFを満たさない。 SQLで「ノートを注文した顧客を探す」ような検索が非常に難しくなるためだ。
対処:1行に1商品が入るよう行を分割する。冒頭の受注テーブルはすでに1NFを満たしている。
第2正規形(2NF)— 部分関数従属を排除する
第2正規形の条件:1NFを満たし、かつ非キー列が主キーのすべてに依存していること
キーワードは部分関数従属の排除だ。
受注テーブルの主キーは「受注番号 + 商品番号」の複合主キーだ。 このとき「顧客名」は「受注番号だけ」で決まる(商品番号は関係ない)。 「商品名」は「商品番号だけ」で決まる(受注番号は関係ない)。
これが部分関数従属だ。主キーの一部だけに依存している列がある状態を指す。
対処:依存関係に基づいてテーブルを分割する。
受注テーブル(分割後)
| 受注番号 | 顧客番号 | 受注明細テーブル |
|---|---|---|
| 1001 | C01 | ← 受注番号で顧客が決まる |
顧客テーブル
| 顧客番号 | 顧客名 |
|---|---|
| C01 | 田中商店 |
受注明細テーブル
| 受注番号 | 商品番号 | 数量 |
|---|---|---|
| 1001 | P01 | 10 |
| 1001 | P02 | 5 |
商品テーブル
| 商品番号 | 商品名 | 単価 |
|---|---|---|
| P01 | ノート | 100 |
| P02 | ペン | 200 |
これで「単価の変更」は商品テーブルの1行を変えるだけで完結する。
第3正規形(3NF)— 推移関数従属を排除する
第3正規形の条件:2NFを満たし、かつ非キー列が非キー列に依存していないこと
キーワードは推移関数従属の排除だ。
例として、社員テーブルを考える。
| 社員番号 | 社員名 | 部署番号 | 部署名 |
|---|---|---|---|
| E01 | 山田 | D01 | 営業部 |
| E02 | 鈴木 | D01 | 営業部 |
| E03 | 田中 | D02 | 開発部 |
主キーは「社員番号」だ。 「部署名」は主キー「社員番号」から直接決まるのではなく、「社員番号 → 部署番号 → 部署名」という推移的な経路で決まる。
これが推移関数従属だ。「営業部」が「セールス部」に名称変更されたとき、複数行を更新しなければならない更新異常が起きる。
対処:依存の経路で分割する。
社員テーブル(分割後)
| 社員番号 | 社員名 | 部署番号 |
|---|---|---|
| E01 | 山田 | D01 |
部署テーブル
| 部署番号 | 部署名 |
|---|---|
| D01 | 営業部 |
| D02 | 開発部 |
部署名の変更は部署テーブルの1行を変えるだけで済む。
試験での出題パターン
選択問題(科目A)
「第2正規形への変換後のテーブル構成として適切なものを選べ」という形式で、テーブル分割前後の候補が4択で示される。 どの列が何に従属しているかを見極めるのがポイントだ。
記述問題(AP午後・DB午前II)
「以下のテーブルの関数従属関係を示せ」「第3正規形に変換せよ」という形式で、関数従属の矢印を書く問題や、テーブルの分割結果を答える問題が出る。
AIで正規化を練習する
正規化の練習には、AIが問題を自動生成してくれる以下のプロンプトが使える。
データベース設計の練習問題を作ってください。
形式:
1. 正規化されていないテーブル定義(5〜8列程度)を提示する
2. このテーブルが持つ部分関数従属または推移関数従属を示す
3. 第3正規形に変換したテーブル群を答えとして用意する
応用情報技術者試験の午後問題レベルで作成してください。自分で分割案を書いた後で「私の解答は正しいですか」と確認することで、独学でも正確なフィードバックが得られる。
まとめ
| 正規形 | 排除するもの | 判断の基準 |
|---|---|---|
| 1NF | 繰り返しグループ | 各セルが単一値か |
| 2NF | 部分関数従属 | 非キー列が主キー全体に依存しているか |
| 3NF | 推移関数従属 | 非キー列が別の非キー列に依存していないか |
正規化は「どこに何が依存しているか」を丁寧に追うことで必ず解けるようになる。 複雑なテーブルでも「まず主キーを決める → 各列の依存先を矢印で書く → 分割する」という3ステップを淡々と実行すること。
