DBの正規化をめっちゃくちゃ簡単に理解する方法

今回はDBの正規化をめちゃくちゃ簡単に理解する方法。
ということで書いていきます。

DBの正規化が難しくて何言ってるかわからん！
ってなってる人はぜひ読んでみてください。

今回はリレーショナルデータベースをもとに話をしています。

先に結論を書いておくと
DBの正規化は**縦と横の重複を取り除く**だけ。
こう考えるとめちゃくちゃ簡単になります。

言ってる意味がわかった方はこの先読まなくても大丈夫です！
わからん、なんとなくという方はぜひ読んでいってください。


## DBの正規化って何？

さて、本題に入る前にざっとDBの正規化についておさらいしましょう。

DBの設計をするにあたって一番大事なことはなんだと思いますか？
それはデータが重複なく取り出しやすい形で保管できるようにすることです。

なぜなら、シンプルにそうなってないDBはDBとしてほとんど機能してないからですね。

DBにデータを入れるのは保管もそうですが、そのデータを取り出して
ユーザーに情報を与えたり、はたまたビジネスに活かしたり。

データを取り出して使うことで効力を発揮するわけです。

ですがデータが重複してたり、取り出しやすい形で保管されてないと
そもそもデータを特定できない、取り出せない、
取り出すとしてもめちゃくちゃ手間がかかる。

という事態になってしまうわけです。

データを取り出して活用することに意味があるわけなので
DBを設計する上では取り出しやすく活用しない状態にするのが大切ということですね。

じゃあそれってどうやればいいの？
ってなったときに使われるのがこのDB正規化です。

正規化というのは**データの繰り返しをなくす**ことです。

そしてその時の手順化したものとして
第一正規系、第二正規系、第三正規系というものがあったりします。

この続きも実はあるんですが、今回は本題と関係ないので省略します。


##  正規化をする手順
さて、ざっと正規化についておさらいをしたところで
ここからは実際に正規化が何をしているのか解説していきます。

と言っても今回の本題はこの**正規化をめちゃくちゃ簡単に理解する**。
という目的で話してるのであくまで簡単な解説にとどめます。

#####  第一正規系
第１正規化で行うことは、主に横方向のデータの繰り返しをなくすことです。

リレーショナルデータベースは縦にどんどんデータを追加するのは得意ですが
横のデータは固定する必要があります。

そこで、横の繰り返し部分を縦に並べるように変更します。

![スクリーンショット 2025-05-18 22.42.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806455/cb16d598-d5b1-405f-b019-2274b60dd03c.png)
↓
![スクリーンショット 2025-05-18 22.42.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806455/c1d3874c-d628-4891-b366-cac8e2e9645c.png)

※[こちらの記事](https://proengineer.internous.co.jp/content/columnfeature/6480#section200)の画像を使わせて頂いてます。

こういった流れですね。
これで第一正規系は完了です。

#####  第二正規系
第二正規系でやることは主に従属関係にあるデータの分離です。

従属関係というのはY＝Xのような式があったとして
YはXの値が決まることで値が決定するのでYはXの従属関係である。
というふうに言ったりします。

まぁ要するに本体とそれに紐づいてくるものの関係みたいなものです。
さて、これをDBで行うとどうなるでしょうか？

![スクリーンショット 2025-05-18 22.50.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806455/7b25ef55-b1b5-4050-a1ef-2b0eb3c377bd.png)
↓
![スクリーンショット 2025-05-18 22.50.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806455/0e1125f9-05db-44ec-b677-5211ba749b03.png)
![スクリーンショット 2025-05-18 22.50.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806455/b4375805-f526-4bc0-9eab-88afe24ae2c7.png)
※[こちらの記事](https://proengineer.internous.co.jp/content/columnfeature/6480#section200)の画像を使わせて頂いてます。

この二つに分離されました。

これは何をしてるのかというと、
まず注文番号が決まることで決定されるのは注文日、合計金額の二つですね。
ユーザー名や発送先住所、送料区分というのは
注文番号が決まったからわかるものではなく。
元々ユーザー情報として登録されてるものなので関係がありません。  

そこで注文番号に従属してる注文日と合計金額以外のデータを
別のテーブルに移しちゃおう！
というのが第二正規系の考え方になります。

こうすることで注文番号を見ればわかる値だけのテーブルとなりデータがすっきりします。

#####  第三正規系
最後に第三正規系では推移的関数従属と呼ばれる
従属関係を分離していきます。

推移的関数従属というのは
「Aが決まればBが決まり、そのBが決まればCが決まる」という場合に、
「Aが決まれば（Bを経由して間接的に）Cが決まる」という関係のことです。

そして、この「間接的に決まるC」が、
Aを主キーとするテーブルに含まれている状態が、
推移的関数従属による問題がある状態です。

難しいと思うのでまた画像で説明すると

![スクリーンショット 2025-05-18 23.04.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806455/cfd6ab3c-de0b-4ab4-80c0-4cd39e974d51.png)
※[こちらの記事](https://proengineer.internous.co.jp/content/columnfeature/6480#section200)の画像を使わせて頂いてます。

こう言ったふうになるわけですね。

これは何をしてるのかというと
ユーザーデータの中にあるユーザーID（主キー）が決まれば
ユーザー名、発送先住所、送料区分がわかる。

ここまではいいのですが送料区分の詳細なデータというのは
ユーザーIDが決まるから決まってるわけじゃないですよね？

例えば上の画像だとユーザーAさんは住所がAなので
送料区分はその他となってますが
これは元々送料区分のデータがあって
それに当てはめるとユーザーAさんは送料区分がその他である。

と考えられるわけです。

つまりユーザーIDの中に送料区分のデータは含まれるけど
その送料区分がまた個別にデータを持ってる状態が推移的関数従属というわけですね。

で、これを別のテーブルに移しましょうというのが第三正規系となります。

## 正規化をめっちゃ簡単にしよう！
さて、だいぶ長く説明をしてきてしまいましたが
ここからがようやく本題です。

と言っても結論は最初に書いた通り
**縦と横の重複をなくすだけ**というシンプルなものなので
そこまで長くはなりません。

ここまでの正規化の手順を読んできて勘のいい方なら
わかるかもしれませんが、実はさっきまで説明してた手順。

この**縦と横の重複をなくす**という簡単な言葉で説明できるんです。

例えば第一正規系でやった手順を見てみると
横方向に商品名と商品単価といったデータが重複してました。

それでやったこととしてはそのデータを縦方向に分割しましたね。

次に第二正規系と第三正規系ですが従属関数とかいうやつを
別テーブルに分割しましょうってことをしてきました。

これは何をしてるかっていうと
第二正規系の時の画像をよく見てみるとユーザー名が縦方向に重複してます。

そこでユーザー名とそれに連なるデータをまとめて別のテーブルに移しましたね。

第三正規系ではさらにその中で送料区分というデータが縦方向に重複してるため
これをまた別のテーブルに切り出すということをしています。  


このように正規系の手順というのは縦と横のデータの重複をなくしてるだけなんです。
推移的関数従属がー！第一、第二、第三だー！
みたいな難しいこと考えなくても縦と横に重複してるデータがなければ
正規化ができてるってことになります。

ちなみにあれ、その理論で言ったら購入履歴のテーブルの注文日は
縦に重複してるけどいいの？って思ったかもしれません。

そこが少し難しいところなんですが
縦の重複で別テーブルに切り出すかどうかの基準は
そのデータが付随してくるデータを持ってくるかどうかになります。

まぁさっきまでの話で言うユーザー名のように
その情報を切り取ったら他のデータも切り取らないといけない。

と言った状況の場合は別テーブルに移す。
そうじゃないならそのままにする。

この考えでOKです。

まとめると

**横方向の重複は縦に並べて解決する**
**縦方向の重複はセットになるデータがあるなら別テーブルに移す**

となります。

これだけだって考えるとめちゃくちゃシンプルだと思えませんか？
自分はこれで正規化について理解しやすくなったので
ぜひ試してみてください。

参考文献
https://proengineer.internous.co.jp/content/columnfeature/6480#section200