夢のかけら

Goエンジニアの技術ブログ

【DB設計】自己参照する多対多の関係を分かりやすく説明する

f:id:lampler:20210427203219p:plain

多対多の復習

自己参照する多対多の関係を理解するには、多対多の関係を理解する必要があります。 大学の授業と生徒の関係を例にとって考えてみます。

まずは学生目線で考えましょう。学生一人が取れる授業の数はいくつでしょうか? 1つでも2つでも3つでも、いくつでもいいですよね。0でもいいかもしれません。 つまり学生:授業 = 1:多となります。

f:id:lampler:20210427201654p:plain

次は授業目線で考えます。一つの授業に参加できる学生は何人でしょうか? 1つの講義にはたくさんの生徒が出席しますね。よって授業:生徒 = 1:多となります。 f:id:lampler:20210427201721p:plain

では学生:生徒の関係はどうなるでしょうか? どちらか一方を1と固定しても、どちらも1:多になってしまいました。このような場合は多:多となります。このように多:多の関係の見つけ方はどちらも1対多になった時となります。

ER図を書いてみよう

それでは学生と授業のデータベース設計をしてみましょう。こんな感じになります。 f:id:lampler:20210427201756p:plain

多対多の関係を管理するには中間テーブルを使います。中間テーブルを見れば、「誰が」「どの授業を」とっているのかが分かります。

select * from students_lectures;

f:id:lampler:20210427201856p:plain

自己参照する多対多の関係

ようやく本題です。今回はTwitterのフォロー関係を例に考えます。 ユーザー1人がフォローできる人数は複数です。よって1対多となります。 一方で1人のユーザーは複数人からフォローされます。したがって、フォローするユーザー:フォローされるユーザーは多:多となります。 f:id:lampler:20210427201935p:plain

ここまでは普通の多対多と同じです。しかし決定的に違う点ひとつがあります。何でしょうか?

ER図を書いてみる

friendshipsテーブルを見れば、「誰が」「誰を」フォローしているかが分かります。 f:id:lampler:20210427202034p:plain

学生と授業の例との違いは何でしょうか?

f:id:lampler:20210427202101p:plain

テーブルが一つ少ないですね。中間テーブルのfriendshipsのカラムであるfollowing_user_idfollowed_user_idはどちらもusersテーブルとつながっています。

どうやって結合する?

中間テーブルを見れば、誰が誰をフォローしているのか、誰が誰によってフォローされているのか、ということが分かります。 f:id:lampler:20210427202146p:plain

フォローしている人もフォローされている人も名前にして表示したい時はどうしましょう? usersテーブルと結合しますよね。

どちらも同じテーブルを参照しているので結合できない?

結合を考えましょう。usersテーブルをもう一つ作らないと結合できないのでしょうか?

答えはNoです。usersテーブルに別名を付けるだけで簡単に結合できます。 usersテーブルとusersテーブルを結合して新しいテーブルを作ります。このように自分自身との結合を自己結合と言います。

自己参照とは?

自己参照とは、参照するテーブル(エンティティ)が自分自身である場合をいいます。今回の例ではフォロー関係を理解するためにusersテーブルが自己参照をしています。

まとめ

  • 多対多の関係は、1対多 + 1対多である。
  • 多対多の時は、1対多となるような中間テーブルを作る。
  • 自己結合とは、1つのテーブルにそれぞれ別名を与えて2つのテーブルと見立てて結合することである。
  • 自己参照する多対多の関係は、多対多 + 自己結合で解決できる。