やさしい図解で学ぶ　中間テーブル　多対多　概念編 

#中間テーブルって？

"join table もしくは junction table"とも呼ばれ、その名の通り、２つのテーブルの中間にもう一つ、それぞれに接続されたテーブルを指します。


↓ER図で見てみると
これが"**中間テーブル**"です。(ER図とは？やER図の見方は[こちら](https://qiita.com/ramuneru/items/32fbf3032b625f71b69d))

<img width="621" alt="スクリーンショット 2019-11-14 16.38.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/992c59a5-c7bd-e267-5939-0e770f768b52.png">

では、簡潔にどんな時に用いるかというと

下図のように２つのテーブルの間に
### " 多対多 "
<img width="583" alt="スクリーンショット 2019-12-07 15.37.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/c39c7f6d-5faf-db66-2c58-954df3a3bca1.png">

という関係性が生まれた時、ある問題を解決する１つの方法としてこの中間テーブルを配置します。


``多対多``の意味がなかなかわかりにくいかと思いますので、これから詳しく図解を使ってちょっとずつ掴んでいきましょう。

#``1.まずは多対多のイメージ``

多対多とは........

例えば、
下の画像のようなプログラミング学習サイトを製作しているとします。

このサイトでは**ユーザー**は学習したい**プログラミングコース**をカスタマイズして選ぶことができるとします。

<img width="623" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/1b0217ea-1d61-1379-b8d7-fb689a8c6893.png">

おそらく必要だとされるテーブルはまずこの２つが想像できます。

1.ユーザー用のもの
2.プログラミングのコース用のもの

2つのテーブルに以下のように名前を決めて...

**①usersテーブル (ユーザー情報用のテーブル)**
**②coursesテーブル (プログラミングの言語情報用のテーブル)**

とします。

**次にテーブル間の関係性をイメージします。**

### ①usersテーブルから見ると
**1userは複数のコースを持っている　→→→　"対多"**

<img width="495" alt="スクリーンショット 2019-11-16 11.12.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/9f3e98bb-c17f-8491-12bc-ba564901e8b3.png">

### ②coursesテーブルから見ると
**1courseは複数のユーザーを持っている　→→→　"対多"**

<img width="543" alt="スクリーンショット 2019-11-16 11.11.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/b2ba272a-dac7-588f-f4fc-1f831262ef83.png">


ということは**usersテーブル**と**coursesテーブル**は

### 対多　＋　対多　＝＝　" 多対多 "

という関係が成り立ちます。

まだよくわからないという方もいると思いますが、実際にテーブルの形で例をみてみましょう。

## ``2. 実際に多対多のテーブルをみてみよう``
とりあえずユーザー３人と言語コース３つで表示しています。
それぞれのテーブルのレコードどちらからも複数のつながりが見えます

<img width="650" alt="スクリーンショット 2019-11-15 17.16.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/21a3c2f9-ddcd-6af8-3328-fc96f3dc4276.png">

つまり、
### " 多対多 "とは関連するテーブルのidを**複数**お互いに持っているということです。

そして、この関係性では下図のように外部キー用のカラムが必要なので
**外部キー**を持たせたテーブルをみてみましょう。
<img width="500" alt="スクリーンショット 2019-11-15 18.12.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/caa8bf7b-4ffe-a802-7728-eda30d6278c5.png">

多対多の関係性の一例ですが、こんな感じになるはずです。

ではもう少し詳しくみてみましょう。

# ``3. 多対多の問題点``
＊前提として1カラムの中にデータは１つずつしか入れられません。
つまり、下の図のように1カラムがuser_idを複数もつことはできません。

<img width="386" alt="スクリーンショット 2019-11-15 18.41.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/072b53aa-0b04-0e9c-f90e-d3efc77725bd.png">


### ★coursesテーブルの中身

userが増えるごとにuser_idカラムを増やさなければいけません。
・図の**courses**テーブルにはとりあえず5人分のuser_idカラムを表示させています。

注目すべきは**<font color="Crimson";>赤枠で囲まれたnull(空)のカラム**

ユーザー一人一人のコース選択が異なるため、図のように空のカラムを持たざるおえない状況が起きてしまいます。


<img width="671" alt="スクリーンショット 2019-11-18 12.41.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/86a3506b-5035-8152-91af-98e05999688b.png">



### ★usersテーブルの中身

courseが増えた時、userの時と同じようにカラムを増やさなければいけません。

こちらも**users**テーブルには8コース分までのcourse_idカラムを持たせています。

同様に**<font color="Crimson";>null(空)のカラム**が多数存在しています。


<img width="795" alt="スクリーンショット 2019-11-18 12.42.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/275a858e-1e70-f4db-2bc8-8b1abf468447.png">




どこがいけないのかわからない場合は**null(からっぽ)のカラム**にとりあえず注目してみてください。

なんだか**ボコボコ、ガタガタ**で、使われていないからっぽのカラムが多数ありますよね。

このような不要なカラムが多数、発生するようなテーブルは
### Multi Column Attribute(マルチカラムアトリビュート)
とよばれ、DB設計において非常に良くない設計であるとされています。

では、どうしたらいいのか。

そんな時用いるのが
### <font color="Crimson";>中間テーブル
です。


#``4. 中間テーブル``

実際に中間テーブルがどんな構造になっているのかもう一度最初のER図をみてみましょう。

<img width="621" alt="スクリーンショット 2019-11-14 16.38.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/e70d8890-7647-0f0a-3014-18312b7fa891.png">

よく見ると
**中間テーブル course_usersテーブル** は
それぞれ接続先のテーブルの外部キー
・**user_id**
・**course_id**
を持っています。


**2.実際に多対多のテーブルをみてみよう**で用いた図を再び見ながら、中間テーブルを作成してみましょう。
<img width="708" alt="スクリーンショット 2019-11-15 17.16.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/44a969d1-4c0c-c78a-d633-fd7042508ef8.png">

この2つのテーブルの間に中間テーブルを設置すると下のような中間テーブルになります。

<img width="726" alt="スクリーンショット 2020-02-06 11.17.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/81580ada-c745-9653-5526-aa6b5221f379.png">


では、さらに詳しく実際の中間テーブルの中身も見てみましょう。


###　中間テーブル：　course_usersテーブル

<img width="758" alt="スクリーンショット 2020-02-20 15.01.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513524/4e582276-ccff-87d2-b700-aae578eae358.png">


要するに今後、**user**の数や**course**の数が増えたとしても
この中間テーブルがあれば、**null（空）**を出すことなく、レコードを追加することができます。


###補足： usersとcoursesの中間テーブルの命名について
中間テーブルの命名は関係性を考えて作成したり、言語により制約などがありますがある程度は自由です。今回はアルファベット順に２つのテーブル名を並べ、最初のテーブルのsを取り除き、**＿**（アンダーバー）でつなげています

なので

cousesテーブル　＋　usersテーブル　＝　course_usersテーブル


#まとめ

###中間テーブルの特徴まとめ
><font color="black">・多対多の関係性があるテーブルの間に設置
<font color="black">・接続する2テーブルの外部キーをもつ
<font color="black">・命名は〇〇〇__〇〇〇s　(基本的にはアルファベット順)もしくは新しく命名

状況によっては中間テーブルをつくったほうがいいケースばかりではありませんが、中間テーブルや多対多の概念について、もやもやしている方はそれがちょっとでもクリアになってもらえたなら嬉しいです。

随時、よりわかりやすくなるよう修正、更新いたします。