はじめに
Laravelの学習中に、1対多のリレーションは組むことができたけれど、多対多の場合のテーブル設計はどう考えれば良いのか、また中間テーブルについてイメージが掴めなかったため、自分なりにまとめてみました。
作成するテーブル
以下の映画テーブルと俳優テーブルを例に考えてみます。
映画テーブル
id | タイトル (title) | 公開年 (release_year) |
---|---|---|
1 | インセプション | 2010 |
2 | タイタニック | 1997 |
3 | アベンジャーズ | 2012 |
俳優テーブル
id | 名前 (name) | 性別 (gender) |
---|---|---|
1 | レオナルド・ディカプリオ | male |
2 | ロバート・ダウニー・Jr | male |
3 | スカーレット・ヨハンソン | female |
1つの映画に複数の俳優が出演します。また1人の俳優は複数の映画に出演します。
つまり2つのテーブルの関係性は、多対多となります。
では、どの映画にどの俳優が出演しているかを紐づけるにはどうしたら良いか考えてみます。
1対多の場合
もし仮に1つの映画に1人の俳優しか出演しないとすれば、2つのテーブルの関係性は、1対多になるので、以下のように外部キーを設定することで出演した俳優を表せます。
映画テーブル
id | タイトル (title) | 公開年 (release_year) | 俳優ID(actor_id) |
---|---|---|---|
1 | インセプション | 2010 | 1 |
2 | タイタニック | 1997 | 1 |
3 | アベンジャーズ | 2012 | 2 |
多対多(不適切な例)
これを踏まえて、多対多のテーブル設計をすると以下のようになります。
映画テーブルに俳優IDを複数設定する(不適切な例1)
id | タイトル (title) | 公開年 (release_year) | 俳優ID(actor_id) | 俳優2ID(actor2_id) | 俳優3ID(actor3_id) |
---|---|---|---|---|---|
1 | インセプション | 2010 | 1 | NULL | NULL |
2 | タイタニック | 1997 | 1 | NULL | NULL |
3 | アベンジャーズ | 2012 | 2 | 3 | NULL |
映画ごとに出演する俳優の数は異なりますので、俳優の数が多い場合を想定して俳優IDのカラムをたくさん設定しておかなければいけないですし、俳優の数が少ない場合には無駄なNULLの値が増えてしまいます。
俳優テーブルに映画IDを設定する(不適切な例2,3)
俳優テーブルに外部キーとして映画IDを設定し、出演映画を管理しようとすると、一人の俳優が複数の映画に出演しているので、複数の映画IDに対応する必要があります。
一つ目のテーブルはレコードが重複してしまいますし、二つ目のテーブルは一つのカラムに複数の値が挿入されるため、不適切です。
id | 名前 (name) | 性別 (gender) | 映画ID(movie_id) |
---|---|---|---|
1 | レオナルド・ディカプリオ | male | 1 |
2 | レオナルド・ディカプリオ | male | 2 |
3 | ロバート・ダウニー・Jr | male | 3 |
4 | スカーレット・ヨハンソン | female | 3 |
id | 名前 (name) | 性別 (gender) | 映画ID(movie_id) |
---|---|---|---|
1 | レオナルド・ディカプリオ | male | 1,2 |
2 | ロバート・ダウニー・Jr | male | 3 |
3 | スカーレット・ヨハンソン | female | 3 |
多対多の設定の場合、映画テーブルや俳優テーブルに相手側の情報を持たせると、データが複雑になり管理が困難になるため、良くないようです。
多対多(中間テーブルの使用)
この問題を解決するため、中間テーブルという別のテーブルを作成して、管理することにします。
映画俳優テーブル
映画ID(movie_id) | 俳優ID(actor_id) |
---|---|
1 | 1 |
2 | 1 |
3 | 2 |
3 | 3 |
一見すると分かりづらいように思いますが、例えば1つ目のレコードは映画ID1の作品に俳優ID1の人が出演していることを表しています。
このように中間テーブルを使用することで、映画ごとに出演する俳優の数が多くなる場合にもカラムを増やす必要がなく、無駄な値も発生しません。
おわりに
記事の作成にあたって、以下のページを参考にさせて頂きました。ありがとうございます。
またテーブルの内容はChatGPTに考えてもらいました。
余裕があれば、Laravelでの多対多のテーブルのリレーションの設定方法についてもまとめたいと思います。