スポンサーリンク

【DB】多対多を実装できない理由

スポンサーリンク

正確には多対多の関係を連関エンティティなしに実装できない理由です。

一対多

まず通常の正しいお話から。一対多の場合は、一の主キーを多の外部キーに設定することで関係を表現できます。

例えば、

  • 著者は一つの本しか書かない
  • 共著あり

という仮定の下では、本が一、著者が多となります。 そのため、著者側に本の主キーを外部キーとして持たせます。

テーブルの中身は以下のようになります。

多対多

通常の前提

  • 共著あり

のみの場合、本と著者は多対多の関係になります。でも一対多が上記で実現できるなら、著者の主キーを外部キーとして設定したらいけるのでは?と考えたのが始まりです。結論では根本から間違っています。

問題1 テーブルを一度に作成できない

そもそも以下のテーブル定義ができません。相互参照となっているため、どちらのテーブルも作成時に一方のテーブルが必要でエラーになります。

create table books(
    book  varchar primary key,
    author  varchar references authors(author)
);

create table authors(
    author varchar primary key,
    book varchar references books(book)
);

したがって、無理やり作ろうとするとまずは外部キー以外を作成して後からテーブル定義を変える方法です。

create table books(
    book varchar primary key
);
create table authors(
    author varchar primary key
);
alter table books add column author varchar references authors(author);
alter table authors add column book varchar references books(book);

そもそもこの時点で不整合なテーブルが一時的に作成されるので嫌ですね。

問題2そもそも意図した多対多にならない

上記で作成したテーブルにレコードを追加します。1対多の時の例と同様に、book1をauthorA, B, Cの3名で作成したとします。

booksのauthorは1対多同様に使用しないのでnullとします(もうこの時点で違和感があるかもしれませんが、1対多の手法をそのまま利用したと仮定します)。続いて、本が多、著者が一となるような関係を追加するために、authorAがbook1, book2を作成したとしてレコードを作成します。この場合、以下のようになります。

これで表現できました。それでは、実はbook2はauthorCも共著者でした、と判明した場合どうなるか?

authorCがbook1, book2を作成しているため、同様であれば以下のように表現されるべきものですが、bookがprimary keyのためこれは実現できません。

したがって、一対多のように外部キーを設定する手法では多対多を表現できません。結局最後に表現したものが連関エンティティで、多対多を表現するためにはbook, authorそれぞれに主キーが設定されているような状態では不可能で、(book, author)のペアで主キーを取る関係が必要ということですね。

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