中間テーブルとは?多対多で崩壊するDBを救う「最強の接着剤」

中間テーブル データベース

あなたがデータベース設計を始めて、最初に頭を抱える瞬間。
それが「多対多」の関係に気づいた時です。

例えば「社員」と「プロジェクト」の関係を想像してください。
一人の社員は、複数のプロジェクトに関わります。
一つのプロジェクトには、複数の社員が参加します。

ここでエクセル脳の持ち主はこう考えます。
「社員テーブルに『参加プロジェクトID』という欄を作って、そこに全部書けばいい」と。

断言します。
それはデジタルな自害です。

1つのマスに「1, 5, 8」とカンマで区切ってデータを詰め込む。
これはデータベースの世界において、最も重い罪の一つ

あとで「プロジェクトID 5に参加している社員一覧をくれ」と言われた瞬間、あなたのシステムは計算処理でパンクして沈黙します。
検索できない。集計できない。削除も面倒。

この「多対多」という複雑な状況を、スッキリ解決する唯一の道具。
それが中間テーブルです。


仲介役がいれば喧嘩しない

中間テーブルとは、複雑な二者の間に入って関係を取り持つ「仲介人」のことです。
あるいは、2つの素材をくっつける「接着剤」の役割を持つ専用のテーブルです。

社員テーブルとプロジェクトテーブルを直接繋ぐことは正しい設計ではありません。

なので、その間に「社員プロジェクト所属テーブル」という新しいテーブルを置きます。
これが中間テーブルです。

やることは単純。
左側の親分のIDと、右側の親分のIDを、ペアにして記録するだけです。

イメージは「参加名簿」です。

  • 社員Aさんが、プロジェクトXに参加する。→ 名簿に「A, X」と書く。
  • 社員Aさんが、プロジェクトYにも参加する。→ 名簿の次の行に「A, Y」と書く。

たったこれだけ。
これにより社員テーブルもプロジェクトテーブルも、互いのことを知らずにクリーンな状態を保てます。

余計なデータを持たず、自分の身元情報(名前やメールアドレス)だけを管理していればいい。
関係性はすべて、この「中間テーブル」が引き受けてくれます。


サンプルで見る:関係の記録

論よりコード。
実際にどう保存されるかを見れば一目瞭然です。

まず、ユーザー(users)がいます。
次に、所属するグループ(groups)があります。
ユーザーは複数のグループに入れますし、グループにはたくさんのユーザーがいます。

ここで作る中間テーブルの名前は、一般的にgroup_useruser_groupsとなります。
中身はこうなります。

// 中間テーブル (user_groups) の中身イメージ

id | user_id | group_id
---+---------+---------
1 | 10 | 99 // ユーザーID:10 は グループID:99 に所属
2 | 10 | 100 // ユーザーID:10 は グループID:100 にも所属
3 | 25 | 99 // ユーザーID:25 も グループID:99 に所属Code language: JavaScript (javascript)

ご覧の通り、ここには具体的な名前やグループ名は入りません。
入っているのは「ID」という背番号だけ

これで名前が変わっても、IDさえ変わらなければ、この関係性は壊れません。


応用:関係にメモを残す

中間テーブルは、ただIDをつなぐだけではありません。
「その関係がいつ生まれたか」や「その関係の強さ」を記録するのにも使えます。

例えば「ユーザー」が「商品」を買う場合。
中間テーブル(この場合は「注文明細」と呼ばれることが多いです)には、IDだけでなく以下の情報を追加できます。

  • 個数(いくつ買ったか)
  • 購入時の価格
  • 購入日時

もし中間テーブルがなければ、これらの情報は置き場所を失います。
ユーザー側に書くわけにもいかないし、商品側に書くわけにもいきません。

二つが出会ったその瞬間の情報は、二つをつなぐ場所にしか記録できないのです。


シンプルこそ最強

中間テーブルは、一見すると「テーブルが増えて面倒」に見えるかもしれません。
しかし、これがあるおかげでシステムは柔軟になります。

社員が退職しても、中間テーブルの行を消すだけでプロジェクト側のデータは無傷です。
逆にプロジェクトが消滅しても、社員データは無傷。

複雑な絡まり合いを「1対多」という単純な線の集合体に分解する。
これがリレーショナルデータベースの真髄であり、美しい設計の第一歩です。

カンマ区切りで逃げるのはやめましょう。
堂々とテーブルを一つ増やし、綺麗なIDのペアを作ってください。

それが、夜に安心して眠れるエンジニアへの近道です。

コメント

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