イメージしてみて、データベースの各テーブルはでっかいパズルのピースみたいなもん。studentsテーブルは誰が勉強してるか、coursesテーブルは何を教えてるか、enrollmentsテーブルは誰がどのコースに登録してるかを知ってる。でもバラバラだと全体像は見えないよね?全部つなげて初めて絵が完成する。そこで登場するのが複数の JOINなんだ。
リアルな現場だと、データはよく関連テーブルに分けて整理されてる。こうすることで構造化できるし、無駄な重複も避けられる。例えば、うちの大学データベースにはこんなテーブルがある:
students— 学生のデータ。enrollments— 学生がどのコースに登録してるかの情報。courses— コースの情報。
もし学生、コース、先生の一覧を全部出したいなら、3つのテーブルをJOINでつなげる必要があるよ。
JOINの実行順序
複数のJOINを使うとき、PostgreSQLは左から右に順番に処理する。つまり、まず最初の2つのテーブルをつなげて、その結果を3つ目のテーブルとつなげて…って感じ。
例:
SELECT *
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id;
- まず
studentsとenrollmentsをstudents.id = enrollments.student_idでつなげる。 - その結果を使って、
enrollments.course_id = courses.idでcoursesとつなげる。
特に大きなテーブルを扱うときは、この順番が超重要。JOINの構造がイケてないと、パフォーマンスがめっちゃ落ちることもある。
例:学生・コース・先生の一覧
例えば、こんなデータのテーブルがあるとする:
studentsテーブル:
| id | name |
|---|---|
| 1 | Otto Song |
| 2 | Maria Chi |
| 3 | Alex Lin |
coursesテーブル:
| id | name | teacher |
|---|---|---|
| 101 | Mathematics | Ellen Moore |
| 102 | Physics | James Okoro |
| 103 | Computer Science | Nina Delgado |
enrollmentsテーブル:
| student_id | course_id |
|---|---|
| 1 | 101 |
| 1 | 103 |
| 2 | 102 |
| 3 | 101 |
クエリ:
SELECT
students.name AS student_name,
courses.name AS course_name,
courses.teacher AS teacher_name
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id;
結果:
| student_name | course_name | teacher_name |
|---|---|---|
| Otto Song | Mathematics | Ellen Moore |
| Otto Song | Computer Science | Nina Delgado |
| Maria Chi | Physics | James Okoro |
| Alex Lin | Mathematics | Ellen Moore |
複数JOINクエリでのフィルタリング
JOINを使ったクエリでも、条件で絞り込んで返すデータ量を減らしたり、クエリを速くしたりできる。例えば、「Mathematics」コースを受講してる学生だけ出したい場合:
SELECT
students.name AS student_name,
courses.name AS course_name
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id
WHERE courses.name = 'Mathematics';
結果:
| student_name | course_name |
|---|---|
| Otto Song | Mathematics |
| Alex Lin | Mathematics |
複数JOINクエリの最適化
大きなテーブルを扱うなら、クエリの最適化はめっちゃ大事。コツをいくつか紹介するね:
- インデックスを使う
インデックスがあると、PostgreSQLは特にキー項目でのJOINが速くなる。enrollmentsテーブルのstudent_idとcourse_idにはインデックスを作っておこう。
インデックス作成例:
CREATE INDEX idx_enrollments_student_id ON enrollments(student_id);
CREATE INDEX idx_enrollments_course_id ON enrollments(course_id);
インデックスについては次のレベルで詳しくやるけど、ここでもちょっと触れておくね。JOINとめっちゃ関係あるから。
- 早い段階でデータを絞り込む
WHERE条件を使って、JOINする前に処理する行数を減らそう。例えば:
SELECT
students.name AS student_name,
courses.name AS course_name
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id
WHERE
courses.teacher = 'Ivan Petrov';
- JOINする行数を最小限にする
2つのテーブルの全レコードをJOINするんじゃなくて、まずサブクエリで絞り込んでからJOINしよう:
SELECT
students.name AS student_name,
courses.name AS course_name
FROM
(SELECT * FROM students WHERE id IN (1, 2)) sub_students
INNER JOIN enrollments ON sub_students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id;
サブクエリ(ネストしたSELECT)については、次のレベルですぐやるからお楽しみに :P
複雑なJOIN例:学生・コース・学部
さらにfacultiesテーブルが追加されたとしよう:
facultiesテーブル:
| id | name |
|---|---|
| 10 | Engineering |
| 20 | Natural Sciences |
coursesテーブルが更新:
| id | name | teacher | faculty_id |
|---|---|---|---|
| 101 | Mathematics | Ellen Moore | 10 |
| 102 | Physics | James Okoro | 20 |
| 103 | Computer Science | Nina Delgado | 10 |
学生・コース・学部の一覧を出すには、さらにJOINを追加しよう:
SELECT
students.name AS student_name,
courses.name AS course_name,
faculties.name AS faculty_name
FROM students
INNER JOIN enrollments ON students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id
INNER JOIN faculties ON courses.faculty_id = faculties.id;
結果:
| student_name | course_name | faculty_name |
|---|---|---|
| Otto Song | Mathematics | Engineering |
| Otto Song | Computer Science | Engineering |
| Maria Chi | Physics | Natural Sciences |
| Alex Lin | Mathematics | Engineering |
複数JOINのSQLクエリはちょっと難しそうだけど、うまく使えば強力なレポートや有益な情報がゲットできる。ちゃんと最適化&構造化すれば、大規模データベースでもバッチリ使える武器になるよ!
GO TO FULL VERSION