「DBをきちんと設計した①」(第1正規化、ER図)

スポンサーリンク
DB
スポンサーリンク

僕はDBをきちんと設計していませんでした。

データ自体は複雑なもの

今回は現在個人開発しているサービスのDBのデータ部分をきちんと論理設計から行いましたので、そのことについてまとめておきます。

今回は正規化を行い、ER図まで落とし込みました。

「達人に学ぶDB設計 徹底指南書」を参考にしています。

論理設計

論理設計は以下のステップで行います。

  1. エンティティの抽出
  2. エンティティの定義
  3. 正規化
  4. ER図の作成

ざっと説明すると、

エンティティは現実世界にあるデータの集合体を指していて、例えば「顧客」とか「店舗」とかです。

システムにはどのようなエンティティ(データ)が必要になるかを抽出するのが1つ目のステップです。

エンティティを抽出したら、各エンティティがどのようなデータを保持するのかを決めます。

これが2つ目のステップ「エンティティの定義」です。

エンティティ(テーブル)に関して、整理する作業がステップ3「正規化」です。

最後のステップ4でエンティティの見取り図として、エンティティ同士の関係を表すER図というものを作成します。

今回は扱うデータは決めているので、今回することは「正規化」と「ER図」の作成です。

また、正規化は基本的に第3正規化まで行うのですが、今回は第1正規化で正規化ができてしまったので、第1正規化まで。

正規化

正規化をしていきます。

まずは例を交えつつ、そもそも第1正規化とは何なのか、そして、第2正規化と第3正規化もどんなものか見ます。

そして、今回は桜の情報が入っている、sakura tableを用いて実施していきます。

第1正規化

第1正規化とは、データベース内のテーブルが「各列に単一の値のみを持つ」というルールを守る状態にすることです。

テーブル内のすべての列(フィールド)は単一の値で構成される必要があり、重複する列や複数の値を持つ列を持つことはできません。

また、データはリストや配列のような形式で格納されてはいけません。

例えば、以下のような「注文」テーブルがあったとします。(主キーに赤いアンダーラインを付けています)

OrderIDCustomerProductsTotal
1John DoeProduct A, Product B$50
2Jane SmithProduct C$20
3Alice LeeProduct D, Product E$70

これは、1つの注文で複数の商品(Products)が含まれているため、このテーブルは第1正規化Fに違反しています。

このテーブルを第1正規化するには、1つのセルに1つの値しか入れないようにテーブルを分割します。

各注文に対して、商品ごとに行を分けます。

「注文」テーブルと「注文詳細」テーブルに分けました。(主キーは赤いアンダーライン、外部キーは青文字にしています。)

✅「注文」テーブル

OrderIDCustomerTotal
1John Doe50
2Jane Smith20
3Alice Lee70

✅「注文詳細」テーブル

OrderIDProductPrice
1Product A25
1Product B25
2Product C20
3Product D35
3Product E35

これで、第1正規化が完了です。

第2正規化

次に第2正規化とはどんなものかを見ていきます。

第2正規化を満たしている状態とは以下の状態を示します。

  • 第1正規化を満たしていること
  • 部分関数従属の排除ができていること

部分関数従属というのは、ということを説明する前に、そもそも関数従属性とはというところから書きます。

関数従属性とはある値xが1つ決まればyが1つに決まる性質を指します。

y = x + 1のようなものですね。

で、部分関数従属性は

「複数列からなる主キーの一部の列に対して従属する列がある状態」

を意味します。

この説明だけだとまだ分かりにくいので、例を示します。

例えば、以下の例では、StudentIDとCourseIDが主キーになっています。

しかし、良く見てみると、

✅クラスコーステーブル(第1正規化済み):

StudentIDCourseIDCourseNameInstructorInstructorPhone
1101MathSmith555-1234
1102ScienceJohnson555-5678
2101MathSmith555-1234
2103HistoryLee555-9876

複合キーは「StudentID」と「CourseID」であり、テーブルの一意な行を特定するためにこの2つの値が必要になります。

上記で、部分関数従属性は「複数列からなる主キー一部の列に対して従属する列がある状態」と書きました。

複数列からなる主キーは「StudentID」と「CourseID」です。

ここで、「CourseName」、「Instructor」、「InstructorPhone」は「CourseID」に依存しています。

「CourseID」が決まれば、この3つは一意に決まるからです。

「CourseID」には従属している状態です。

しかし、「StudentID」には依存していません。

これが、一部の列に対して従属する列がある状態です。

この部分関数従属性を無くすようにします。

具体的には、部分従属しているカラムを別のテーブルに分割します→「CourseID」のみ依存しているカラムを別のテーブル(今回はCourseInfo テーブル)に移動します。(主キーは赤いアンダーライン、外部キーは青文字にしています。)

✅StudentCourse テーブル

StudentIDCourseID
1101
1102
2101
2103

✅CourseInfo テーブル

CourseIDCourseNameInstructorInstructorPhone
101MathSmith555-1234
102ScienceJohnson555-5678
103HistoryLee555-9876

これで各カラムが完全に主キー(または複合キー)に依存するようになりました。

第3正規化

非キー属性(キーではないカラム)が他の非キー属性に依存しないようにテーブルを分割します(これを「推移的関数従属の排除」と言います)

第2正規化した「CourseInfo」 テーブルを見てみてみます。(上記のものを再掲)

CourseIDCourseNameInstructorInstructorPhone
101MathSmith555-1234
102ScienceJohnson555-5678
103HistoryLee555-9876

講師の情報(Instructor と InstructorPhone)が入っていますが、これらは CourseID ではなく、Instructor に依存しています。

これを第3正規化するために、講師に関する情報を別のテーブルに分けます。

✅StudentCourse テーブル(そのまま変更なし)

StudentIDCourseID
1101
1102
2101
2103

✅CourseInfo テーブル

CourseIDCourseNameInstructorID
101Math1
102Science2
103History3

✅InstructorInfo テーブル

InstructorIDInstructorInstructorPhone
1Smith555-1234
2Johnson555-5678
3Lee555-9876

これにより、InstructorPhone が InstructorID にのみ依存し、第3正規化が完了しました(推移的関数従属が排除されました)

今回の場合

今回扱うテーブルは以下のようなテーブルです。

桜の情報が載っているテーブルで、season_listカラムとして見ごろの月のデータが入っています。

idspot_nameseason_listetc…
1Spot A3,4
2Spot B4,5

「3,4」、「4,5」というように、値が列に複数入っています。

これでは第1正規化に違反してしまっています。

なので、以下のように第1正規化を実施します。

sakura_table(元のテーブル、season_list カラムは削除)

idspot_name
1Spot A
2Spot B

sakura_season_table(シーズンごとに分割した新しいテーブル)

idseason
13
14
24
25

今回の場合は第2正規化を満たしています。

しかし、第3正規化は満たしていませんので、第3正規化もする必要があります。

sakura_tableではidではなくspot_nameカラムに依存しているので、テーブルを分けます。

idとspot_nameをもとのsakura_tableに残して、残りを別のsakura_info_tableに移しました。

こんな感じ👇

sakura_table(元のテーブル、season_list カラムは削除)

idspot_name
1Spot A
2Spot B

sakura_info_tableは以下。

spot_namesakura_genre
Spot Aソメイヨシノ
Spot Bエドヒガンザクラ

ER図

ER図とはデータベース設計界隈でデファクトスタンダードな設計図です。

今回はER図を作成するにあたって、以下のサイトを使用しました。

dbdiagram.io - Database Relationship Diagrams Design Tool
Quick and simple free tool to help you draw your database relationship diagrams and flow quickly using simple DSL language.

DDLから自動でER図を作成してくれます。

今回作成されたER図は以下です。

タイトルとURLをコピーしました