基本情報のデータベース正規化とは?第1〜第3正規形を図解で理解
第1正規形、第2正規形と言われても、表をどこで分ければいいのかがわからない。
正規化の問題で、用語の説明は読んだのに、いざ表を前にすると手が止まっていませんか?
先に答えをお伝えします。
データベースの正規化とは、同じデータが何度も書かれている表を、矛盾が起きにくい形に分けていく手順です。第1正規形では繰り返しの項目をなくし、第2正規形では主キーの一部だけで決まる項目を切り出し、第3正規形では主キー以外の項目で決まる項目を切り出します。
つまり、それぞれの段階で、何によって値が決まるのかを見て、表を分けていきます。この記事では、この記事のために作った受注表を使い、非正規形から第3正規形まで、1段ずつ分割していきます。
基本情報技術者試験の全体像を先に確かめたい人は、こちらの親記事が参考になります。
【関連記事】基本情報技術者試験とは?試験内容・難易度・勉強法を初心者向けに解説
正規化はなぜ必要?データの重複が起こす3つの問題¶
正規化の手順に入る前に、なぜ表を分ける必要があるのかを確かめておきましょう。理由が分かると、どこで分ければよいかの判断がしやすくなります。
この記事で使う受注表¶
ここからは、文房具の卸売店が使う受注表を例にします。1件の注文で、複数の商品をまとめて受けることがあるものとします。
| 受注番号 | 受注日 | 顧客番号 | 顧客名 | 商品番号 | 商品名 | 単価 | 数量 |
|---|---|---|---|---|---|---|---|
| A01 | 11/1 | C1 | 山田商店 | P1, P2 | ノート, ペン | 100, 80 | 3, 5 |
| A02 | 11/2 | C2 | 川口文具 | P1 | ノート | 100 | 2 |
| A03 | 11/3 | C1 | 山田商店 | P3 | 消しゴム | 50 | 4 |
受注番号A01の行には、商品の情報が2つずつ入っています。このように、1つのマスに複数の値が入っている状態の表を、非正規形と呼びます。
この記事では、単価は商品ごとに1つに決まっているものとして考えます。
重複があると起きる3つの異常¶
この表には、山田商店という顧客名や、ノートの単価が何度も出てきます。同じデータが複数の場所にあると、データを変えるときに次のような問題が起きます。
| 問題の名前 | 起きること | この表での例 |
|---|---|---|
| 更新時の異常 | 一部の行だけ書き換え、データが食い違う | 山田商店の店名変更をA01だけ直し、A03を直し忘れる |
| 追加時の異常 | 必要な情報がそろわず、行を追加できない | 注文がまだ無い新商品を登録できない |
| 削除時の異常 | 行を消すと、残したい情報まで消える | A03を取り消すと、消しゴムの単価が分からなくなる |
正規化は、こうした問題を防ぐために、1つの事実を1か所にだけ書く形へ表を分ける作業です。山田商店の名前が1か所にしか無ければ、書き換えも1回で済みます。
正規化を読むための3つの言葉¶
正規化の説明には、いくつかの専門用語が出てきます。先に3つだけ押さえておきましょう。
主キーとは、表の中の1行を特定するための列です。受注番号が決まれば受注日が1つに決まる、というように、ある列の値で別の列の値がただ1つに決まる関係を、関数従属と呼びます。
外部キーとは、ほかの表の主キーを参照するための列です。分けた表どうしは、この外部キーでつながります。
第1正規形|1つのマスに1つの値だけにする¶
第1正規形とは、すべてのマスに値が1つずつ入っている表のことです。A01の行のように、1つのマスに商品が2つ入っている状態をなくします。
繰り返しの項目を行に分ける¶
商品番号から数量までの4列は、1件の注文の中で繰り返し出てくる項目です。これを、1つの商品につき1行になるよう書き直します。
| 受注番号 | 受注日 | 顧客番号 | 顧客名 | 商品番号 | 商品名 | 単価 | 数量 |
|---|---|---|---|---|---|---|---|
| A01 | 11/1 | C1 | 山田商店 | P1 | ノート | 100 | 3 |
| A01 | 11/1 | C1 | 山田商店 | P2 | ペン | 80 | 5 |
| A02 | 11/2 | C2 | 川口文具 | P1 | ノート | 100 | 2 |
| A03 | 11/3 | C1 | 山田商店 | P3 | 消しゴム | 50 | 4 |
A01は2行に分かれ、受注日や顧客名は両方の行にくり返し書かれます。どのマスにも値が1つだけになったので、これで第1正規形です。
第1正規形の主キーを考える¶
この表では、受注番号だけでは行を1つに決められません。A01が2行あるからです。
受注番号と商品番号の2つを組み合わせると、どの行も1つに決まります。このように、複数の列を組み合わせた主キーを複合キーと呼びます。
第1正規形になっても、重複はまだ残っています。むしろ、受注日や顧客名が書かれる回数は増えました。ここから先の段階で、重複を減らしていきます。
第2正規形|主キーの一部で決まる項目を切り出す¶
第2正規形とは、第1正規形であり、主キー以外のすべての列が、主キー全体で決まる表のことです。主キーの一部だけで決まる列を、別の表に切り出します。
何で値が決まるかを確かめる¶
主キーは受注番号と商品番号の組です。それぞれの列が、どちらの列で決まるのかを1つずつ確かめてみましょう。
| 列 | 何で決まるか | 判断 |
|---|---|---|
| 受注日 | 受注番号だけ | 主キーの一部で決まる |
| 顧客番号 | 受注番号だけ | 主キーの一部で決まる |
| 顧客名 | 受注番号だけ | 主キーの一部で決まる |
| 商品名 | 商品番号だけ | 主キーの一部で決まる |
| 単価 | 商品番号だけ | 主キーの一部で決まる |
| 数量 | 受注番号と商品番号の両方 | 主キー全体で決まる |
数量は、どの注文の、どの商品かが分からないと決まりません。一方、受注日は受注番号が分かれば決まり、商品名は商品番号が分かれば決まります。
このように、主キーの一部だけで値が決まる関係を、部分関数従属と呼びます。第2正規形は、部分関数従属をなくした表です。
3つの表に分ける¶
受注番号で決まる列、商品番号で決まる列、両方で決まる列の3つに分けます。下線を引く代わりに、主キーの列名に「(主キー)」と付けて表します。
受注(受注番号(主キー), 受注日, 顧客番号, 顧客名)
商品(商品番号(主キー), 商品名, 単価)
受注明細(受注番号(主キー), 商品番号(主キー), 数量)
受注明細表の受注番号と商品番号は、それぞれ受注表と商品表を参照する外部キーにもなっています。この2つの列を手がかりにすれば、分けた表をいつでも元の形に戻せます。
商品表ができたので、注文の無い新商品も登録できるようになりました。A03を取り消しても、消しゴムの単価は商品表に残ります。
第3正規形|主キー以外の列で決まる項目を切り出す¶
第3正規形とは、第2正規形であり、主キー以外の列によって決まる列が無い表のことです。最後に残った重複を、ここで取り除きます。
推移関数従属を見つける¶
第2正規形の受注表を見ると、顧客名は今も受注のたびに書かれています。山田商店はA01とA03の2回です。
| 受注番号 | 受注日 | 顧客番号 | 顧客名 |
|---|---|---|---|
| A01 | 11/1 | C1 | 山田商店 |
| A02 | 11/2 | C2 | 川口文具 |
| A03 | 11/3 | C1 | 山田商店 |
顧客名は、受注番号から直接決まっているわけではありません。受注番号で顧客番号が決まり、顧客番号で顧客名が決まる、という2段階の関係です。
受注番号 → 顧客番号 → 顧客名のように、主キー以外の列を経由して決まる関係を、推移関数従属と呼びます。第3正規形は、推移関数従属をなくした表です。
顧客の表を切り出す¶
顧客番号で決まる顧客名を、顧客表として切り出します。受注表には、顧客表を参照するための顧客番号だけを残します。
顧客(顧客番号(主キー), 顧客名)
受注(受注番号(主キー), 受注日, 顧客番号)
商品(商品番号(主キー), 商品名, 単価)
受注明細(受注番号(主キー), 商品番号(主キー), 数量)
これで第3正規形になりました。山田商店の名前は顧客表の1か所にしか無いので、店名が変わっても1行を書き換えるだけで済みます。
最初の1つの表が、4つの表に分かれたことになります。それぞれの表には、1種類の事実だけが書かれています。
3つの正規形の違いを並べて比べる¶
ここまでの3段階を、何をなくしたのかという観点で表にまとめます。試験で正規形を問われたときは、この表の順に確かめていくと判断しやすくなります。
| 正規形 | なくすもの | この記事での分け方 |
|---|---|---|
| 第1正規形 | 1つのマスに入った複数の値(繰り返し項目) | 商品ごとに1行にした |
| 第2正規形 | 主キーの一部で決まる列(部分関数従属) | 受注・商品・受注明細に分けた |
| 第3正規形 | 主キー以外の列で決まる列(推移関数従属) | 受注から顧客を切り出した |
主キーが1つの列だけの表は、主キーの一部というものが無いので、第1正規形であれば第2正規形の条件も満たします。部分関数従属を考えるのは、複合キーの表のときだけと覚えておくと迷いません。
正規化の問題を解く練習¶
ここまでの内容を使って、自作の問題で練習してみましょう。答えを見る前に、列ごとに何で値が決まるかを書き出してから考えてみてください。
練習1|何正規形かを判断する¶
次の表は、社員番号を主キーとする社員表です。部署名は、部署コードによって1つに決まるものとします。
社員(社員番号(主キー), 氏名, 部署コード, 部署名)
どのマスにも値は1つなので、第1正規形は満たしています。主キーが1列だけなので、部分関数従属もありません。
一方、社員番号 → 部署コード → 部署名という推移関数従属があります。したがって、この表は第2正規形ですが、第3正規形ではありません。
第3正規形にするには、部署(部署コード(主キー), 部署名)を切り出し、社員表には部署コードだけを残します。
練習2|分けた表を結合で戻す¶
正規化で表を分けると、元の受注表の形で見たいときは、表をつなぎ直す必要があります。このときに使うのが、SQLの結合(JOIN)です。
たとえば、受注表と顧客表を顧客番号で結合すれば、受注番号と顧客名を並べた表が作れます。表を分けても情報が失われないのは、外部キーで元に戻せるからです。
結合の仕組みや、内部結合と外部結合の違いは、こちらの記事で詳しく解説しています。
【関連記事】基本情報のSQL結合(JOIN)がわからない!内部結合・外部結合を図解
正規化の問題で間違えやすい点¶
最後に、正規化の問題でつまずきやすい点を表にまとめます。答えが合わなかったときは、どれに当てはまるかを確かめてみてください。
| 間違えやすい点 | 起きること | 確かめ方 |
|---|---|---|
| 主キーを1列だと思い込む | 部分関数従属を見落とす | 1行を決めるのに必要な列をすべて挙げる |
| 第2と第3の違いを混同する | 正規形の判断を誤る | 主キーの一部か、主キー以外の列かを見る |
| 列の名前だけで判断する | 問題文の条件と違う従属関係を考える | 何で値が決まるかは問題文の説明で確かめる |
| 分けた表に外部キーを残し忘れる | 表を元の形に戻せなくなる | 切り出した表の主キーを、元の表に残す |
とくに3つ目は大切です。商品の単価が注文ごとに変わる会社なら、単価は受注明細表に置くべきです。正規化の問題では、問題文に書かれた業務の決まりに従って、何で値が決まるかを判断しましょう。
正規化とSQLは科目Aの中でつながっている¶
正規化とSQLは、どちらも科目Aのデータベース分野で学ぶ内容です。表を分ける理由を知っていると、SQLで表を結合したり、条件で行を絞ったりする問題の意味も理解しやすくなります。
SELECTやWHEREで行と列を取り出す基本を確かめたい人は、こちらの記事を読んでみてください。
【関連記事】基本情報のSQL問題の解き方|SELECT・WHERE・ORDER BYを例題で解説
何で決まるかを追う力は科目Bにも生きる¶
正規化では、ある列の値が何によって決まるのかを、1つずつ確かめました。この、値がどこから来るのかを丁寧に追う姿勢は、科目Bでプログラムの変数を追うときにも役立ちます。
科目Bでは、擬似言語で書かれたプログラムを読み、変数の値がどう変わるかを追う問題が中心です。擬似言語とは、試験のために決められた書き方でプログラムを表したものです。科目Bの出題内容は、こちらの記事で確かめられます。
【関連記事】基本情報技術者試験の科目Bとは?擬似言語・アルゴリズム対策を初心者向けに解説
私たちの Giji Academy では、擬似言語の講座を記法の基礎から条件分岐・繰返し・配列・アルゴリズム、科目B対策まで段階的に用意しています。擬似言語シミュレーターを使えば、プログラムをブラウザ上で1行ずつ実行し、変数の値が変わる様子を確かめられます。
一部の教材と入門レベルの練習問題は、無料会員のまま使えます。講座は擬似言語の講座一覧から始められます。
まとめ¶
データベースの正規化は、同じデータが何度も書かれる表を、更新・追加・削除で矛盾が起きにくい形に分ける手順です。1つの事実を1か所にだけ書くことを目指します。
第1正規形では1つのマスに複数の値が入らないようにし、第2正規形では主キーの一部で決まる列を切り出します。第3正規形では、主キー以外の列で決まる列を切り出します。
どの段階でも、列の値が何によって決まるのかを確かめるのが出発点です。小さな表を自分で作り、1段ずつ分けてみる練習を重ねれば、正規化の問題は着実に得点できるようになります。