正規化とテーブル定義書の作成
概要
- 日程: Day 7 / セッション 2
- 時間: 10:00-11:00(60分)
- 形式: 実習
- ゴール: 情報モデル定義書のデータを第三正規形まで正規化し、型・桁数・制約まで定義したテーブル定義書(DBMS不使用チームはファイル設計書)を時間内に完成できる
- 学習形式: ハンズオン実習(AIサポートあり)
導入(5分)
前のセッションで「正規化のなぜ」を学びました。受注伝票デモで第一→第二→第三と段階的に整理する流れが見えたと思います。
ここからは自チームのデータで実際に手を動かします。
問いかけ:自チームの情報モデル定義書(Day4成果物)の中で、「繰り返しが起きそうな項目」はどれですか?
→ 例:「会員の予約一覧」「商品のタグ一覧」「ユーザのコメント一覧」。これらが第一正規化の対象候補です。
本編(10分)
1. テーブル定義書とは
テーブル定義書とは、1つのテーブルが持つカラムの設計を一覧化した表です。実装者はこの表を見てDDLを書き、設計通りのテーブルを作ります。
テーブル定義書のテンプレート
| 項目 | 内容 | 例 |
|---|---|---|
| テーブル物理名 | DBに作る名前 | members |
| テーブル論理名 | 日本語名 | 会員 |
| 概要 | 何を保存するか | 会員の基本情報 |
カラム一覧
| No | 物理名 | 論理名 | 型 | 桁数 | NULL | 主キー | 外部キー | デフォルト | 制約 | 説明 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | id | 会員ID | INTEGER | - | NO | YES | - | 自動採番 | - | 一意な会員ID |
| 2 | name | 氏名 | VARCHAR | 50 | NO | - | - | - | - | 表示用の氏名 |
| 3 | メールアドレス | VARCHAR | 100 | NO | - | - | - | UNIQUE | ログインID兼ねる | |
| 4 | created_at | 作成日時 | TIMESTAMP | - | NO | - | - | CURRENT_TIMESTAMP | - | レコード作成日時 |
ここがポイント
- 物理名は小文字スネークケース・複数形(例:members, order_details)
- 論理名は日本語で書く(実装者・レビュアー全員が読める)
- 型と桁数は実データの最大長から決める(メール100、氏名50など)
- NOT NULL を初期値に。NULL を許す列だけ理由を持って許可
2. 命名規約の決め方
チーム内で命名規約を最初に決めます。途中で変えると混乱します。
| 観点 | 推奨 | 理由 |
|---|---|---|
| テーブル名 | 小文字スネーク・複数形 | members, order_details |
| カラム名 | 小文字スネーク | first_name |
| 主キー | id(または table_id) | 統一すると JOIN が書きやすい |
| 外部キー | 参照先_id | member_id, product_id |
| 日時カラム | created_at / updated_at | ISO的に統一 |
| 真偽値 | is_xxx / has_xxx | is_active, has_image |
コラム:命名規約の流派
世の中には「テーブルは単数形派(member)」と「複数形派(members)」があります。Ruby on Rails は複数形、Java の JPA はデフォルト単数形が多いです。どちらが正解ではなく、チーム内で統一することが大事です。命名規約は チームの方言。一度決めたらブレない、これが守れているチームはコードもきれいに育ちます。
3. ファイル設計書(DBMS不使用チーム向け)
DBMSを使わないチームは、テーブル定義書の代わりに ファイル設計書 を作ります。
| 項目 | 内容 | 例 |
|---|---|---|
| ファイル物理名 | 実際のファイル名 | orders.json |
| ファイル論理名 | 日本語名 | 受注ファイル |
| 形式 | データ形式 | JSON / CSV |
| 概要 | 何を保存するか | 受注情報の一覧 |
項目一覧
| No | 項目名 | 論理名 | 型 | NULL | 例 | 説明 |
|---|---|---|---|---|---|---|
| 1 | order_id | 受注ID | number | NO | 1001 | 一意な受注ID |
| 2 | order_date | 受注日 | string (ISO8601) | NO | "2026-06-20" | 受注日 |
| 3 | customer_id | 顧客ID | number | NO | 101 | customers.json を参照 |
| 4 | details | 明細 | array | NO | 下記参照 | 受注明細の配列 |
ファイル設計書でも、マスタとなるデータは別ファイルに切り出すことで、正規化の精神を活かします。
実習・演習(40分)
課題
自チームの情報モデル定義書(Day4成果物)を入力として、テーブル定義書(またはファイル設計書)を作成します。
進め方(推奨タイムテーブル)
| 時間 | 作業 |
|---|---|
| 5分 | 命名規約の合意(テーブル名・カラム名・主キー) |
| 10分 | 情報モデルごとに第一正規化(繰り返し項目の分離) |
| 10分 | 第二・第三正規化(外部キーの定義) |
| 10分 | 各カラムの型・桁数・NULL可否・制約を埋める |
| 5分 | AIにレビューを依頼し、抜け漏れを確認 |
成果物
- テーブル定義書(DBMS使用チーム)
- ファイル設計書(DBMS不使用チーム)
すべての情報モデルを網羅し、主キー・外部キー・型・桁数・制約が定義されていること。
ヒント
AI協働の進め方
正規化の各段階で、次のように AI と対話しましょう。
私たちのチームの情報モデルは「予約」「会員」「店舗」です。
予約には以下の属性があります:予約番号、予約日、会員名、会員電話、店舗名、店舗住所、利用人数、利用時間。
(1) これを第一正規化したテーブル構成を提案して
(2) (1)の結果を第二・第三正規化した最終形を提案して
(3) 各テーブルの推奨カラム型・桁数も併せて教えて
(4) 残っている異常があれば指摘して
AI の答えをそのまま使わず、チームで吟味して採否を決めるのがポイントです。
よくあるレビュー観点
- 主キーが定義されているか
- 外部キーの参照先が存在するか
- VARCHARの桁数に根拠があるか(「とりあえず255」を避ける)
- 日時カラムの型は揃っているか
- NULL を許す列に理由があるか
💬 AIに聞いてみよう
- 「
membersテーブルのemail列に UNIQUE 制約を付けるべきか?理由とともに教えて」 - 「メールアドレスは何文字あれば足りる?RFCではどう定義されている?」
- 「論理削除(is_deleted 列)と物理削除はどちらを選ぶべき?」
- 「JSON ファイル管理で複合主キーが必要になったらどうする?」
まとめ(5分)
今日のセッションの要点を3つに絞ります。
- テーブル定義書は 物理名・型・桁数・NULL可否・主キー・外部キー・制約 を必ず明記する
- 命名規約は最初に合意。途中変更は混乱の元
- AI に 正規化の各段階を検証 させると抜け漏れが減る
次のセッション(Session 3)では、ここで作ったテーブルどうしの関係を ER図 で見える化します。
🔄 振り返りチェック
- チームの命名規約を3つ以上挙げられる
- テーブル定義書のカラム属性を6つ以上挙げられる
- 自チームの全情報モデルがテーブル化されている
- 主キー・外部キーが全テーブルに定義されている
- AI に正規化のレビューを依頼した
補足資料
- 前セッション資料:
Day7_Session01_内部設計とDBMS_正規化の考え方.md - Day4 情報モデル定義書(自チーム成果物)
- 参考: 各DBMSのデータ型一覧(MySQL / PostgreSQL / SQLite)
学習ガイド
想定される質問と回答例
| 質問 | ヒント |
|---|---|
| INT と BIGINT どちらを使うべき? | 想定レコード数が21億を超える可能性があれば BIGINT。会員管理なら INT で十分 |
| VARCHAR(255) を全列に使うのは? | 桁数の意味が消えバリデーションも甘くなる。氏名は50、住所は200のように意味で決める |
| 主キーを文字列にしてもいい? | UUID など可。ただし JOIN 性能とインデックスサイズに注意 |
| 外部キー制約は本番でも有効にすべき? | 整合性は守られるが、削除順序の制約も増える。チームで方針を決める |
| ファイル設計書とテーブル定義書、どちらが楽? | ファイルは初期は楽だが、検索・更新の負担が増える。データ量が増える前に DBMS への移行を検討 |
つまずきやすいポイント
| つまずきポイント | ヒント |
|---|---|
| カラム名の付け方が揺れる | 一覧表を1枚作って全員が参照する。AI に「この列名はチームの規約に合っているか」を聞く |
| 桁数が決められない | 「現実の最大長 × 2」を初期値にする。例:氏名=50、メール=100 |
| デフォルト値を入れ忘れる | 「作成日時」「更新日時」「論理削除フラグ」など共通カラムを最初にチーム標準として決める |
| 外部キーの方向が逆 | 「多側が外部キーを持つ」と覚える(会員1:予約多 なら予約テーブルに member_id) |
| 中間テーブルの主キー | 2つの外部キーの組み合わせを複合主キーにするのが基本(次セッションで扱う) |