3秒でわかる
両側がそれぞれ複数の相手とつながる関係のこと。RDBでは中間テーブルを1枚挟み、1対多を2本に分解して表現するのが定石です。
もう少し詳しく
どういうものか
多対多は、Aから見てBが複数あり、同時にBから見てもAが複数ある関係です。学生と講義、記事とタグ、社員とプロジェクトが典型例です。1人の学生は複数の講義を取り、1つの講義には複数の学生がいます。この関係は、片方のテーブルに外部キーを1本足すだけでは表せません。
なぜ必要か
表そのものは行と列の平面なので、1つのセルに複数のIDを入れる形にはできません。そこで、両者のIDを1行ずつ持つ中間テーブル(関連テーブル、交差テーブル)を作り、多対多を「1対多が2本」に分解します。この分解をしないと、タグ列にカンマ区切りで値を詰め込むような設計になり、検索も集計も破綻します。
具体例
CREATE TABLE students (
id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE courses (
id INT PRIMARY KEY,
title VARCHAR(100)
);
-- 中間テーブル。2列そろえて<a href="/glossary/primary-key" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">主キー</a>にすると重複登録を防げる
CREATE TABLE enrollments (
student_id INT,
course_id INT,
taken_at DATE,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES students(id),
FOREIGN KEY (course_id) REFERENCES courses(id)
);
SELECT s.name, c.title
FROM students s
<a href="/glossary/join" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">JOIN</a> enrollments e ON e.student_id = s.id
JOIN courses c ON c.id = e.course_id;つまずきやすいところ
中間テーブルに複合主キーを付け忘れると、同じ学生と同じ講義の行が何度も入り、件数を数えたときに水増しされます。もうひとつは、中間テーブルを「ただのつなぎ」と考えてしまうことです。履修日や役割など、関係そのものに属性が付くことは多く、そのときは中間テーブルが独立した実体になります。名前も student_course より enrollments のような意味のある名詞にしたほうが後で読みやすくなります。
似た用語との違い
1対多は片側だけが複数で、外部キー1本で足ります。多対多は両側が複数なので、必ずテーブルが1枚増えます。
覚え方
「両方から見て複数か」を口に出して確かめます。学生から見て講義は複数、講義から見て学生も複数なので多対多です。片方だけが複数なら1対多で、テーブルは増えません。