【DB設計】自己参照する多対多の関係を分かりやすく説明する
多対多の復習
自己参照する多対多の関係を理解するには、多対多の関係を理解する必要があります。 大学の授業と生徒の関係を例にとって考えてみます。
まずは学生目線で考えましょう。学生一人が取れる授業の数はいくつでしょうか? 1つでも2つでも3つでも、いくつでもいいですよね。0でもいいかもしれません。 つまり学生:授業 = 1:多となります。
次は授業目線で考えます。一つの授業に参加できる学生は何人でしょうか? 1つの講義にはたくさんの生徒が出席しますね。よって授業:生徒 = 1:多となります。
では学生:生徒の関係はどうなるでしょうか? どちらか一方を1と固定しても、どちらも1:多になってしまいました。このような場合は多:多となります。このように多:多の関係の見つけ方はどちらも1対多になった時となります。
ER図を書いてみよう
それでは学生と授業のデータベース設計をしてみましょう。こんな感じになります。
多対多の関係を管理するには中間テーブルを使います。中間テーブルを見れば、「誰が」「どの授業を」とっているのかが分かります。
select * from students_lectures;
自己参照する多対多の関係
ようやく本題です。今回はTwitterのフォロー関係を例に考えます。 ユーザー1人がフォローできる人数は複数です。よって1対多となります。 一方で1人のユーザーは複数人からフォローされます。したがって、フォローするユーザー:フォローされるユーザーは多:多となります。
ここまでは普通の多対多と同じです。しかし決定的に違う点ひとつがあります。何でしょうか?
ER図を書いてみる
friendshipsテーブルを見れば、「誰が」「誰を」フォローしているかが分かります。
学生と授業の例との違いは何でしょうか?
テーブルが一つ少ないですね。中間テーブルのfriendships
のカラムであるfollowing_user_id
とfollowed_user_id
はどちらもusersテーブルとつながっています。
どうやって結合する?
中間テーブルを見れば、誰が誰をフォローしているのか、誰が誰によってフォローされているのか、ということが分かります。
フォローしている人もフォローされている人も名前にして表示したい時はどうしましょう? usersテーブルと結合しますよね。
どちらも同じテーブルを参照しているので結合できない?
結合を考えましょう。usersテーブルをもう一つ作らないと結合できないのでしょうか?
答えはNoです。usersテーブルに別名を付けるだけで簡単に結合できます。 usersテーブルとusersテーブルを結合して新しいテーブルを作ります。このように自分自身との結合を自己結合と言います。
自己参照とは?
自己参照とは、参照するテーブル(エンティティ)が自分自身である場合をいいます。今回の例ではフォロー関係を理解するためにusersテーブルが自己参照をしています。
まとめ
- 多対多の関係は、1対多 + 1対多である。
- 多対多の時は、1対多となるような中間テーブルを作る。
- 自己結合とは、1つのテーブルにそれぞれ別名を与えて2つのテーブルと見立てて結合することである。
- 自己参照する多対多の関係は、多対多 + 自己結合で解決できる。