📖 読了目安 約19分
この記事の目次

テーブル定義書の読み方

テーブル定義書は、データベースのテーブル構造を定義したドキュメントです。SQL作成やデータ操作で必ず参照します。

テーブル定義書とは

役割

  • テーブル(データの入れ物)の構造を定義
  • カラム(列)の仕様を定義
  • 制約(主キー、外部キーなど)を定義
  • インデックス(検索高速化)を定義

いつ使うか

場面 使い方
SQL作成時 カラム名、型の確認
実装時 データ構造の理解
テスト時 データ確認
障害調査時 データの追跡

テーブル定義書の構成

よくある構成要素

項目 内容 確認ポイント
テーブル名 物理名・論理名 命名規則
カラム定義 各列の詳細 型、桁数、NULL
主キー レコードを一意に識別 どのカラムか
外部キー 他テーブルとの関連 参照先
インデックス 検索高速化 どのカラムに
備考 補足情報 運用ルール

カラム定義の要素

項目 内容 確認すること
カラム名(物理名) 実際のDB名 英数字、命名規則
カラム名(論理名) 日本語名 何のデータか
データ型 VARCHAR, INTなど 格納できるデータ
桁数 最大文字数/精度 入力値の制限
NULL NULL許可/不可 必須かどうか
デフォルト 初期値 未指定時の値
備考 補足説明 注意事項

よく使うデータ型

文字列型

説明 使い分け
CHAR(n) 固定長文字列 桁数が決まっているもの(郵便番号など)
VARCHAR(n) 可変長文字列 一般的な文字列
TEXT 長い文字列 備考、説明文など

数値型

説明 使い分け
INT 整数 ID、数量など
BIGINT 大きい整数 大きなID、カウンターなど
DECIMAL(p,s) 固定小数点 金額など精度が必要なもの
FLOAT 浮動小数点 計算結果など

日時型

説明 使い分け
DATE 日付 生年月日など
TIME 時刻 開始時刻など
DATETIME / TIMESTAMP 日時 作成日時、更新日時など

【サンプル】テーブル定義書の実例

usersテーブル定義書

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
テーブル定義書
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

■ 基本情報
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
テーブル名(物理)  : users
テーブル名(論理)  : ユーザー
スキーマ            : public
説明                : サービス利用者の情報を管理
作成日              : 2024/01/15
更新日              : 2024/02/01

■ カラム定義
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

| No | 物理名 | 論理名 | データ型 | 桁数 | NULL | PK | FK | デフォルト | 備考 |
|----|--------|--------|----------|------|------|----|----|-----------|------|
| 1 | id | ユーザーID | BIGINT | - | × | ○ | - | AUTO | 自動採番 |
| 2 | email | メールアドレス | VARCHAR | 256 | × | - | - | - | ユニーク |
| 3 | password_hash | パスワード | VARCHAR | 256 | × | - | - | - | bcryptハッシュ |
| 4 | name | 氏名 | VARCHAR | 100 | × | - | - | - | - |
| 5 | phone | 電話番号 | VARCHAR | 15 | ○ | - | - | NULL | ハイフン含む |
| 6 | status | ステータス | INT | - | × | - | - | 1 | 1:有効, 2:停止, 9:退会 |
| 7 | last_login_at | 最終ログイン日時 | DATETIME | - | ○ | - | - | NULL | - |
| 8 | created_at | 作成日時 | DATETIME | - | × | - | - | CURRENT_TIMESTAMP | - |
| 9 | updated_at | 更新日時 | DATETIME | - | × | - | - | CURRENT_TIMESTAMP | ON UPDATE |

■ インデックス
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

| インデックス名 | カラム | 種別 | 備考 |
|---------------|--------|------|------|
| PRIMARY | id | 主キー | - |
| uk_users_email | email | ユニーク | メールアドレスの一意制約 |
| idx_users_status | status | 通常 | ステータス検索用 |

■ 外部キー
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
なし

■ 備考
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- パスワードは平文で保存しない(bcryptでハッシュ化)
- 退会時はstatus=9に更新(物理削除しない)
- statusの値は共通コードテーブルを参照

ordersテーブル定義書

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
テーブル定義書
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

■ 基本情報
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
テーブル名(物理)  : orders
テーブル名(論理)  : 注文
説明                : 注文情報を管理

■ カラム定義
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

| No | 物理名 | 論理名 | データ型 | 桁数 | NULL | PK | FK | デフォルト | 備考 |
|----|--------|--------|----------|------|------|----|----|-----------|------|
| 1 | id | 注文ID | BIGINT | - | × | ○ | - | AUTO | 自動採番 |
| 2 | user_id | ユーザーID | BIGINT | - | × | - | ○ | - | users.id |
| 3 | order_number | 注文番号 | VARCHAR | 20 | × | - | - | - | 'ORD-' + YYYYMMDD + 連番 |
| 4 | total_amount | 合計金額 | DECIMAL | 10,0 | × | - | - | 0 | 税込み |
| 5 | status | ステータス | INT | - | × | - | - | 1 | 後述 |
| 6 | ordered_at | 注文日時 | DATETIME | - | × | - | - | - | - |
| 7 | shipped_at | 発送日時 | DATETIME | - | ○ | - | - | NULL | - |
| 8 | created_at | 作成日時 | DATETIME | - | × | - | - | CURRENT_TIMESTAMP | - |
| 9 | updated_at | 更新日時 | DATETIME | - | × | - | - | CURRENT_TIMESTAMP | - |

■ ステータス値
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

| 値 | 意味 | 遷移元 | 遷移先 |
|----|------|--------|--------|
| 1 | 注文中 | - | 2, 9 |
| 2 | 決済完了 | 1 | 3, 9 |
| 3 | 出荷準備中 | 2 | 4, 9 |
| 4 | 発送済み | 3 | 5 |
| 5 | 配達完了 | 4 | - |
| 9 | キャンセル | 1, 2, 3 | - |

■ インデックス
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

| インデックス名 | カラム | 種別 | 備考 |
|---------------|--------|------|------|
| PRIMARY | id | 主キー | - |
| uk_orders_number | order_number | ユニーク | 注文番号の一意制約 |
| idx_orders_user | user_id | 通常 | ユーザー検索用 |
| idx_orders_status | status | 通常 | ステータス検索用 |
| idx_orders_ordered | ordered_at | 通常 | 日付検索用 |

■ 外部キー
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

| 制約名 | カラム | 参照先 | ON DELETE | ON UPDATE |
|--------|--------|--------|-----------|-----------|
| fk_orders_user | user_id | users(id) | RESTRICT | CASCADE |

■ 備考
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- 注文番号は業務で使う識別子(ORD-20240115-0001形式)
- ユーザーが退会してもordersは残る(RESTRICT)
- キャンセル後の復活はできない

読み方のポイント

1. 主キー(PK)を確認する

  • レコードを一意に識別するカラム
  • JOINの条件に使う
  • 通常はidという名前

2. 外部キー(FK)を確認する

  • 他テーブルとの関連
  • JOINの条件に使う
  • 参照整合性の制約

3. NULL可/不可を確認する

NULL 意味 実装への影響
× NULL不可 必須入力、INSERT時に必須
NULL可 省略可能、NULLチェック必要

4. デフォルト値を確認する

  • INSERT時に省略できるか
  • どんな値が入るか

5. インデックスを確認する

  • どのカラムに検索条件がつくか
  • ユニーク制約があるか

SQLを書くときの活用

SELECT文の例

-- usersテーブルから有効なユーザーを取得
SELECT id, email, name, phone
FROM users
WHERE status = 1
ORDER BY created_at DESC;

JOIN文の例

-- ordersとusersを結合
SELECT o.id, o.order_number, o.total_amount,
       u.name, u.email
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 2;

INSERT文の例

-- usersに新規レコード追加
INSERT INTO users (email, password_hash, name, phone)
VALUES ('user@example.com', 'hashed_password', '山田太郎', '03-1234-5678');
-- id, status, created_at, updated_at はデフォルト値が入る

よくある疑問

Q: 物理名と論理名の違いは?
  • 物理名:実際のDBで使う名前(英数字)
  • 論理名:人間が理解するための名前(日本語)
Q: ユニーク制約とは?

同じ値のレコードを入れられない制約。メールアドレスなど重複不可の項目に設定。

Q: ON DELETE RESTRICT とは?

参照先のレコードを削除しようとしたとき、参照しているレコードがあるとエラーになる設定。

設定 動作
RESTRICT 削除不可(エラー)
CASCADE 一緒に削除
SET NULL NULLに更新

テーブル定義書でよくある落とし穴

落とし穴 対策
カラム名を間違える コピペで確実に
型の違いを見落とす 型を確認してから実装
NULL可を見落とす NULLハンドリングを忘れない
桁数制限を見落とす 桁数を確認して入力値をチェック

【実践】テーブル定義書からエンティティを作る

サンプルのusersテーブル定義書から、Javaのエンティティクラスを作成してみましょう。

ステップ1:基本構造を決める

テーブル基本情報を見て、クラスの基本構造を決めます。

import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@Table(name = "users")  // テーブル名(物理): users
public class User {
    // カラム定義をもとにフィールドを定義
}

ステップ2:主キーを設定する

カラム定義のPK列を見て、主キーを設定します。

// No.1: id - BIGINT, PK, AUTO
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

ステップ3:各カラムをフィールドにマッピングする

@Entity
@Table(name = "users")
public class User {

    // No.1: id - BIGINT, PK, AUTO
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // No.2: email - VARCHAR(256), NOT NULL, ユニーク
    @Column(nullable = false, length = 256, unique = true)
    private String email;

    // No.3: password_hash - VARCHAR(256), NOT NULL
    @Column(name = "password_hash", nullable = false, length = 256)
    private String passwordHash;  // スネークケース→キャメルケース変換

    // No.4: name - VARCHAR(100), NOT NULL
    @Column(nullable = false, length = 100)
    private String name;

    // No.5: phone - VARCHAR(15), NULL許可
    @Column(length = 15)
    private String phone;  // nullableはデフォルトtrue

    // No.6: status - INT, NOT NULL, デフォルト1
    @Column(nullable = false)
    private Integer status = 1;  // デフォルト値を設定

    // No.7: last_login_at - DATETIME, NULL許可
    @Column(name = "last_login_at")
    private LocalDateTime lastLoginAt;

    // No.8: created_at - DATETIME, NOT NULL, デフォルトCURRENT_TIMESTAMP
    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;

    // No.9: updated_at - DATETIME, NOT NULL, ON UPDATE
    @Column(name = "updated_at", nullable = false)
    private LocalDateTime updatedAt;

    // ライフサイクルコールバック
    @PrePersist
    protected void onCreate() {
        createdAt = LocalDateTime.now();
        updatedAt = LocalDateTime.now();
    }

    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
    }

    // getter/setter は省略
}

カラム定義とアノテーションの対応表

カラム定義の項目 JPAアノテーション
PK @Id + @GeneratedValue 主キー
NOT NULL(×) @Column(nullable = false) 必須カラム
NULL許可(○) @Column(nullableは省略可) 任意カラム
桁数 @Column(length = n) VARCHAR(256)
ユニーク制約 @Column(unique = true) メールアドレスなど
物理名がJava命名規則と異なる @Column(name = "...") snake_case → camelCase
デフォルト値 フィールド初期化 = 1

外部キーがある場合

ordersテーブルのuser_id(FK)を例に、リレーションを設定します。

@Entity
@Table(name = "orders")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // No.2: user_id - BIGINT, FK → users(id)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    @Column(name = "order_number", nullable = false, length = 20, unique = true)
    private String orderNumber;

    @Column(name = "total_amount", nullable = false)
    private BigDecimal totalAmount;

    @Column(nullable = false)
    private Integer status = 1;

    @Column(name = "ordered_at", nullable = false)
    private LocalDateTime orderedAt;

    @Column(name = "shipped_at")
    private LocalDateTime shippedAt;  // NULL許可

    // ... created_at, updated_at
}

ステータス値の対応

テーブル定義書にステータス値の一覧がある場合、Enum化すると便利です。

// ordersテーブルのステータス値をEnumに
public enum OrderStatus {
    ORDERING(1, "注文中"),
    PAID(2, "決済完了"),
    PREPARING(3, "出荷準備中"),
    SHIPPED(4, "発送済み"),
    DELIVERED(5, "配達完了"),
    CANCELLED(9, "キャンセル");

    private final int code;
    private final String label;

    OrderStatus(int code, String label) {
        this.code = code;
        this.label = label;
    }

    public int getCode() { return code; }
    public String getLabel() { return label; }

    public static OrderStatus fromCode(int code) {
        for (OrderStatus status : values()) {
            if (status.code == code) return status;
        }
        throw new IllegalArgumentException("Unknown code: " + code);
    }
}

テーブル定義書からエンティティを作るときのポイント

  1. 物理名と論理名:物理名(スネークケース)をDBに、論理名をコメントに
  2. NULL可否:NOT NULLのカラムにはnullable = falseを付ける
  3. 桁数:VARCHARの桁数はlengthで指定
  4. 外部キー@ManyToOne/@OneToManyで関連を表現
  5. デフォルト値:Javaのフィールド初期化で設定

関連ドキュメント