WebサービスなどでDB設計をするとき、よく適当にテーブルを設計して「このテーブルにもID一覧持たせておけばよくないかな」と考えてしまいがちな人向けに、RDBでなぜ「中間テーブル」を用いるのかを「多対多」をキーワードになるべくまとめます。
情報モデル
以下のようなモデルを例にします:
-
User
: ユーザー -
Post
: 投稿記事 -
Tag
: タグ -
PostTag
: タグと投稿の関係を管理する中間テーブル
問題起点
「Postについているタグ名を持たせたいならpost
テーブルに tag_name
からなる列を持たせれば良いじゃん?」と思うことがあります。しかしこれはRDBの設計思想に反します。
ユーケース: Post ID=1 の投稿に付けられたタグを取得したい
例:
SELECT t.id, t.name
FROM PostTag pt
JOIN Tag t ON pt.tag_id = t.id
WHERE pt.post_id = 1;
これにより、Postに繋がる複数のタグをもれなく取得できます。
なぜ中間テーブルを作るの?
1. 多対多を表現するには、テーブルを分ける必要がある
1つのPostに複数のTag、そのTagは別のPostにも使われる。
これが「多対多 (N:N)」の構造。
RDBでは、多対多を表現するときに「中間テーブル」を作ります:
Post (1) ---< PostTag >--- (1) Tag
2. 1つの行に複数値を持たせない (1NF)
NG例:
post_id | tag_names |
---|---|
1 | "アウトドア,一人OK,自然" |
- 検索しづらい
- 表示ゆれが起きやすい
- 更新が難しい
3. Tagはマスタデータ
Tagは名前や色情報を含んだ「定義情報」として別て管理するのがメンテナンス性が高い。
- Tagの名前を変更するところは1ーexecuteで手忙で管理できる
- Post側のデータは変える必要がない
4. JOINすれば欲しい情報はすぐに取れる
タグ名が欲しければ、JOINするだけ。
まとめ
項目 | 理由 |
---|---|
中間テーブルを作る | 多対多を表現するため |
Tag名を持たせない | Tagテーブルから取れば良い |
同じTagを複数使い回せる | データ重複を避けるため |
変更性が高い | 1か手を入れるだけで全体に反映 |
後記
今回のメモは、自分でDBを設計する際に「なぜ中間テーブルを作るのか」を説明できるようにするための理解の基礎を整理したものです。
もっと難しいテーマ(グループ化や縦方スケーリング)を考える前に、この基本を理解していることが重要です。
全体のテーブル設計の流れやユーケースの定義、ER図化なども別記事で何回かに分けて書く予定です。