データベースを扱うには正規化というものを行う必要がある。
その正規化とはなんぞや。
正規化とは、「効率よくデータを扱うために、整理すること」かな。
なぜ、そんなことをしなければならないか。
データを管理する方法はいくつかあるが、主に世の中で使用されているものは、行( タプル, レコード )、 列( カラム、 属性 )で関係 を表現する、関係データベース( リレーショナルデータベース ) と言われるものである。
この関係データベースは、行、列の2次元構造である。
実際の仕事で使用されているような情報は、2次元で表現するには複雑すぎる。
それを無理に関係データベースにすると、色々と残念なことが起きる。
それを上手く管理するためのデータへと分解するのが正規化という手法なんだと思う。
ここからは、具体的例を用いて説明する。
非正規形
例えば、武器や防具等を売る商いをしているGomoCool商会という会社があるとする。
もちろん商売をする上で、何を誰に何個売る予定だとかは、紙なりメモなりに何かに残すだろう。
その時、こんな感じかなっていう例が以下の図。
はじまりの村の小さなよろずやとの取引と、お得意様のリバー王国の騎士団との取引の2件があるとする。
取引1回のたびに、かぶらない取引番号をつけている。
このデータを2次元のデータベースに入れようとするために、下記の図のように少し修正する。
見て分かるように、1つの取引番号対して、明細番号や商品コード等が繰り返し項目になっている。
このようのデータでは、行単位の情報でしか登録できない関係データベースには、登録したくても、登録できない。
こうのような生のデータのことを非正規形と読んでいる。
第1正規形
それで、このデータを何とか無理くりでもデータベースに登録しようとした場合、1つの行にするために繰返し項目を無くして、単一値と呼ばれる形ににする。
これでデータベースに登録することはできる形にはなったが、なんだか悪くなってないか?っていうのが第1正規形と呼ばれる形である。
関数従属性
さて、このテーブルの主キーはどれになるだろうか。
主キーとは、テーブルの中で行がひとつに絞り込める必要な値、もしくは値の組み合わせを指す。
このテーブルの場合主キーは{取引番号, 明細番号}の組み合わせになる。
取引番号と明細番号が決まれば、行は1つに絞り込める。
この、ある属性が決まれば、自ずと決まるという仕組みを、関数従属性という。
このテーブルの場合、取引番号と明細番号が決まれば、商品コードや商品の注文数が決まる。
この関数従属性を、{取引番号,明細番号}→{商品コード,注文数,・・}といった感じで書ける。
まぁ、小難しい言葉だけど、「ユーザーIDがわかれば、ユーザー名も普通分かるでしょ」っていうことを正しく書くとそういう言葉になる。
第2正規形
さてさて、ここから第2正規形にする。
難しい言葉でかくと、
第2正規形とは、主キーを構成するキーの一部が、部分関数従属しない。
第2正規化とは、部分関数従属性を取り除くこと。
である。
まじで意味不明だが、要は主キーが複数のキーの組み合わせ(複合キー)の場合に、全部組み合わせとかしなくても、片方のキーだけで、決まっちゃうものがある場合、部分関数従属性があるという。
(*{取引番号, 明細番号, 第三のキー} と3つで主キーの場合、そのうち2つあれば決まっちゃう物がある場合も同じ。)
例えば、今回の例の場合だと、主キーは { 取引番号、 明細番号 }の複合キーだけど、そのうちの取引番号が決まれば、取引予定日とか、取引相手の顧客コード、顧客名が決まる。
別に明細番号とかいらない。
なので、この部分だけ別テーブルに切りだしちゃう。すると下の図のようになる。
これが第2正規形。
第3正規形
次は第3正規形にする。
これは、簡単。 見れば気持ち悪い所がちょこちょこ残ってるよね。
「商品コードとかつけてるくせに商品管理するテーブルがないじゃねーか!」とか。
商品テーブル作ってないもんだから、薬草の値段変えたかったら、薬草の取引に関する部分全部変えなきゃダメとか、新しい商品追加したくても、取引明細テーブルにしか商品情報が書いてないから、登録できないとか、アホみたいなことを更新時異常と言うんだけど、お目にかかることはあまりない。
さて、
第3正規形は、第2正規形であり、推移的関数従属性がない。
第3正規化は、推移的関数従属性を取り除くこと。
また難しい言葉が出てきたけど、主キーじゃないやつを非キーって言うんだけど、非キーの中でも、これが決まれば実際全部求まるよね?な部分を取り除けば第三正規形になる。
例えば、{取引番号,明細番号}→{商品コード}→{商品名、単価} ってなってるところを推移的関数従属と言う。
取引番号と明細番号が決まれば、商品コードとか商品名とか一意にきまる。けど、そもそも商品コードが決まれば商品名とか普通に決まってるでしょ。商品コードだけわかってればよくね?ってことですね。
なので、気持ち悪いところを別テーブルに切りだしちゃうと以下のようになる。
また、単価 x 注文数 = 小計 みたいな、計算で導出される導出項目と呼ばれるものは正規化では要らなくなる。
テーブルをガッチャンコ(結合)して、元のテーブルを作り直すときに計算で求めればいいからね。
ちなみに、正規化でバラバラとテーブルを分けたけど、これは結合というSQLを使った操作で簡単に元のテーブルを作れる。
こういう、バラバラにして管理しやすくしたけど情報自体は無くなってないし、すぐ元に戻せる分解を、情報無損失分解という。まぁ、あまり使わない言葉だね。
あとがき
ざっくりとだけど、これがデータベースの正規化になる。
ちなみに、ボイスコット正規形、第4正規形、第5正規形というのもあるんだけど、気持ち悪い設計をしなければ普通は、第3正規形の時点で第5正規形まで満たしていることが多い。
だから、仕事では第3正規形までやっとけばだいたい大丈夫と言われてる。
これで正規形がどいうものかはざっくりと分かったんじゃなかろうか。
しかし、何でもかんでも第三正規形にすればいいってもんじゃないこともある。
例えば、取引予定は第三正規形でいいけど、取引結果などは第三正規形はしないとかね・・・。
この記事最後まで読んでくれた方は以下の記事もお勧めですよー。
詳細な解説、とてもありがたいです!
お役に立てて何よりです(^^)
実務じゃないのでアレですけど、実際は取引明細から商品単価を排除してしまうと、
商品テーブルの商品価格を変えたときに取引時点の商品価格がわからなくなってしまうので
小計が導出できなくなります。
コメントありがとうございます。
ご指摘の通り導出項目を消すと結果が求められなくなるので、この例では分かりにくいのですが取引予定リスト(現時点のお見積り的な?)としています。
一応最後の一文に匂わしているのですが、この記事では難しくなるので、詳しくは別記事のマスターデータとトランザクションデータって結局なんぞやに書き出しております。
>例えば、取引予定は第三正規形でいいけど、取引結果などは第三正規形はしないとかね・・・。
他のサイトでは主キーと読んだり複合キーと読んだりいまいちつかめなかったのですが、こちらのブログが非常に分かりやすかったです。ありがとうございます。
お役にたててよかったです。
ちなみに複合キーだと使いにくいのでWebサイトだとサロゲートキーを立ててそっちを主キーとして使ったりもします。