正規化とは ― 第1正規形から第3正規形まで
正規化は、
正規化とは、データの重複と矛盾を防ぐために表を分割する手順
正規化とは、1つの表に詰め込まれたデータを、重複や矛盾が起きない形に分割していく手順です。表を設計するときに、同じデータが何度も出てくる、更新するたびに食い違うといった問題を防ぐために行います。
例えば、注文のたびに顧客名を同じ表に書き込むと、同じ顧客名を何度も入力することになります。入力のたびに表記がずれると、同じ人なのに別人として扱われてしまいます。正規化は、この重複と、重複から起きる矛盾を防ぐために表を分けます。
分けた表どうしは、主キーと外部キーでつなぎます。主キーは、表の1行を一つに決める列です。外部キーは、別の表の主キーを指す列です。分けた表を共通の列でつなぎ直す操作を結合と呼びます。結合は関係演算の記事で説明しています。
正規化は1段階で終わりません。非正規形から第1正規形、第2正規形、第3正規形へと、1段ずつ段階を踏んで進めます。段階が進むごとに、表が分割されていきます。
テーブルを作る前に、顧客や注文のような管理の対象(エンティティ)をどう関連付けるかを決める段階もあります。その考え方は、E-R図の記事で説明しています。正規化は、テーブルができた後に行う手順です。データベース設計の段階でいえば、正規化は表と主キーを決める論理設計の作業です。データベースやDBMSそのものの仕組みは、データベースとはの記事で説明しています。
注文・顧客・商品の表を1段ずつ分けて確かめる
例として、注文と顧客と商品を1つの表にまとめたものを分割します。次の図のボタンを押すと、表が1段ずつ分割されていきます。
| 注文IDPK | 顧客ID | 顧客名 | 商品 |
|---|---|---|---|
| 1001 | C01 | 山田 | P01 ノート 3個 P02 ペン 10個 |
| 1002 | C02 | 佐藤 | P01 ノート 1個 |
注文1001では、ノートとペンの2商品を同時に頼んでいます。1つの「商品」セルの中に、商品ID・商品名・数量の組が複数入っています。この状態を非正規形と呼びます。
| 注文IDPK | 顧客ID | 顧客名 | 商品IDPK | 商品名 | 数量 |
|---|---|---|---|---|---|
| 1001 | C01 | 山田 | P01 | ノート | 3 |
| 1001 | C01 | 山田 | P02 | ペン | 10 |
| 1002 | C02 | 佐藤 | P01 | ノート | 1 |
商品ごとに行を分け、1つのセルに1つの値だけが入るようにしました。これが第1正規形です。主キーは、注文IDと商品IDを組み合わせた複合キーになります。
顧客ID・顧客名は、主キーのうち注文IDだけで決まります。商品名も、主キーのうち商品IDだけで決まります。複合キーの一部だけで決まる列があるこの状態を、部分関数従属と呼びます。
| 注文IDPK | 顧客ID | 顧客名 |
|---|---|---|
| 1001 | C01 | 山田 |
| 1002 | C02 | 佐藤 |
| 商品IDPK | 商品名 |
|---|---|
| P01 | ノート |
| P02 | ペン |
| 注文IDPK | 商品IDPK | 数量 |
|---|---|---|
| 1001 | P01 | 3 |
| 1001 | P02 | 10 |
| 1002 | P01 | 1 |
顧客ID・顧客名を注文表に、商品名を商品表に分けました。これが第2正規形です。どの表でも、主キー以外の列は、主キーの全体がそろって初めて決まります。この状態を完全関数従属と呼びます。
注文表の中では、顧客名は顧客IDで決まり、顧客IDは注文IDで決まります。主キー以外の列が、別の主キー以外の列を経由して決まるこの状態を、推移関数従属と呼びます。
| 注文IDPK | 顧客ID |
|---|---|
| 1001 | C01 |
| 1002 | C02 |
| 顧客IDPK | 顧客名 |
|---|---|
| C01 | 山田 |
| C02 | 佐藤 |
| 商品IDPK | 商品名 |
|---|---|
| P01 | ノート |
| P02 | ペン |
| 注文IDPK | 商品IDPK | 数量 |
|---|---|---|
| 1001 | P01 | 3 |
| 1001 | P02 | 10 |
| 1002 | P01 | 1 |
顧客名を顧客表として独立させ、注文表には顧客IDだけを残しました。これが第3正規形です。どの表でも、主キー以外の列は主キーだけで決まり、他の主キー以外の列を経由しません。
第1正規形:くり返しの列を行に分けて、1セル1値にする
非正規形の表では、1つのセルに複数の値が入っています。上の図の例では、注文1001の「商品」セルに、ノートとペンの2件分が入っていました。この複数件分の並びを、くり返し部分と呼びます。
第1正規形は、このくり返し部分を行に分け、1つのセルに1つの値だけが入るようにした状態です。商品ごとに行を分けると、1つの注文が複数行にまたがります。そのため、主キーは注文IDと商品IDを組み合わせた複合キーになります。複合キーで行が1つに決まる様子は、主キーと外部キーの記事に図があります。
第2正規形:部分関数従属している列を、別の表に分ける
第1正規形の注文明細表には、顧客ID・顧客名・商品名という列もありました。このうち顧客ID・顧客名は、複合主キーのうち注文IDだけで決まります。商品名も、複合主キーのうち商品IDだけで決まります。
このように、複合主キーの一部だけで、主キー以外の列の値が決まる状態を部分関数従属と呼びます。一方、数量は注文IDと商品IDの両方がそろわないと決まりません。主キーの全体がそろって初めて決まる状態を、完全関数従属と呼びます。
第2正規形は、部分関数従属している列を別の表に分けた状態です。顧客ID・顧客名を注文表に、商品名を商品表に分けると、注文明細表の主キー以外の列は、主キーの全体に完全関数従属する数量だけになります。
第3正規形:推移関数従属している列を、さらに別の表に分ける
第2正規形の注文表には、注文ID・顧客ID・顧客名が残っています。顧客名は顧客IDで決まり、その顧客IDは注文IDで決まります。
主キー以外の列が、別の主キー以外の列を経由して決まる状態を推移関数従属と呼びます。注文表の中では、注文IDから顧客ID、顧客IDから顧客名という2段階で顧客名が決まります。これが推移関数従属に当たります。
第3正規形は、推移関数従属している列をさらに別の表に分けた状態です。顧客名を顧客表として独立させ、注文表には顧客IDだけを残します。これで、どの表でも、主キー以外の列はほかの主キー以外の列を経由せず、主キーから直接決まるようになります。分けた表を外部キーでつなぐときのSQLの書き方は、CREATE TABLEと制約の記事で説明しています。
参考にした資料
- E. F. Codd "Further Normalization of the Data Base Relational Model"(IBM Research Report RJ909、1971年)
練習問題(全5問)
正解:データの
正規化は、
正解:
非正規形は、
正解:部分関数従属
複合主キーの
正解:推移関数従属
主キー以外の
正解:推移関数
第2正規形から
選んでから「採点する」を押すと、解説つきで答え合わせができます。
関連記事
おすすめの本 PR
セキュリティとデータベースは、基本情報技術者試験の対策本でまとめて学べます。

