準備
以下の2つのテーブルを準備する。
- students
- 学生IDと学生名を保存。
- courses
- 学科IDと学科名を保存。
studentsテーブルの作成とデータ登録のクエリー。
| 1 2 3 4 5 6 7 8 9 10 | CREATE TABLE students (   id INT,   name VARCHAR(10) ); INSERT INTO students VALUES   (1, '安藤'),   (2, '伊藤'),   (3, '宇藤'),   (4, '江藤'); | 
実行結果。
| 1 2 3 4 5 6 7 8 9 10 | mysql> SELECT * FROM students; +------+--------+ | id   | name   | +------+--------+ |    1 | 安藤   | |    2 | 伊藤   | |    3 | 宇藤   | |    4 | 江藤   | +------+--------+ 4 rows in set (0.00 sec) | 
coursesテーブルの作成とデータ登録のクエリー。
| 1 2 3 4 5 6 7 8 9 10 | CREATE TABLE courses (   id INT,   name VARCHAR(10) ); INSERT INTO courses VALUES   (10, '数学'),   (11, '物理学'),   (12, '化学'),   (13, '天文学'); | 
実行結果。
| 1 2 3 4 5 6 7 8 9 10 | mysql> SELECT * FROM courses; +------+-----------+ | id   | name      | +------+-----------+ |   10 | 数学      | |   11 | 物理学    | |   12 | 化学      | |   13 | 天文学    | +------+-----------+ 4 rows in set (0.00 sec) | 
JOIN~総当たり
FROM句のテーブルに対して単にJOINでテーブルを指定すると、2つのテーブルの全要素の組み合わせが得られる。
| 1 2 3 | SELECT students.name, courses.name FROM students JOIN courses; | 
実行結果。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | +--------+-----------+ | name   | name      | +--------+-----------+ | 江藤   | 数学      | | 宇藤   | 数学      | | 伊藤   | 数学      | | 安藤   | 数学      | | 江藤   | 物理学    | | 宇藤   | 物理学    | | 伊藤   | 物理学    | | 安藤   | 物理学    | | 江藤   | 化学      | | 宇藤   | 化学      | | 伊藤   | 化学      | | 安藤   | 化学      | | 江藤   | 天文学    | | 宇藤   | 天文学    | | 伊藤   | 天文学    | | 安藤   | 天文学    | +--------+-----------+ 16 rows in set (0.00 sec) | 
結合テーブル
studentsテーブルとcoursesテーブルの結合テーブルを準備する。各学生の履修学科に関するデータ。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | CREATE TABLE student_courses (   student_id INT,   course_id INT ); INSERT INTO student_courses VALUES   (1, 10),   (1, 11),   (3, 10),   (3, 11),   (3, 13),   (4, 11),   (4, 13); | 
クエリーの実行結果、
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | mysql> SELECT * FROM student_courses; +------------+-----------+ | student_id | course_id | +------------+-----------+ |          1 |        10 | |          1 |        11 | |          3 |        10 | |          3 |        11 | |          3 |        13 | |          4 |        11 | |          4 |        13 | +------------+-----------+ 7 rows in set (0.00 sec) | 
INNER JOIN
結合テーブルに基づいて、2つのテーブルの両方に存在するデータを取り出す。studentsとcoursesの積集合に相当する。INNERは書かなくても内部結合になる。
| 1 2 3 4 5 6 7 | SELECT   カラム1,   カラム2,   ..... FROM テーブル1 [AS エイリアス1] [INNER] JOIN テーブル2 [AS エイリアス2]   ON [テーブル1].キー1 = [テーブル2].キー2; | 
student_coursesテーブルとstudentsテーブルを結合するクエリーの例。結合の結果、studentsテーブルから学生名を得られる。
| 1 2 3 4 5 6 7 | SELECT   stcs.student_id,   st.name,   stcs.course_id FROM student_courses AS stcs JOIN students AS st ON stcs.student_id = st.id; | 
実行結果。
| 1 2 3 4 5 6 7 8 9 10 11 12 | +------------+--------+-----------+ | student_id | name   | course_id | +------------+--------+-----------+ |          1 | 安藤   |        10 | |          1 | 安藤   |        11 | |          3 | 宇藤   |        10 | |          3 | 宇藤   |        11 | |          3 | 宇藤   |        13 | |          4 | 江藤   |        11 | |          4 | 江藤   |        13 | +------------+--------+-----------+ 7 rows in set (0.00 sec) | 
3つのテーブルの場合、JOIN ... ON句を並べればよい。以下の例ではcoursesテーブルも結合して、学科名も得ている。
| 1 2 3 4 5 6 7 8 9 10 | SELECT   stcs.student_id,   st.name AS student_name,   stcs.course_id,   cs.name AS course_name FROM student_courses AS stcs JOIN students AS st   ON stcs.student_id = st.id JOIN courses AS cs   ON stcs.course_id = cs.id; | 
実行結果。student_coursesテーブルは学生IDと学科IDしか持っていないが、studentsテーブル、coursesテーブルと結合することで学生名と学科名を使えるようになる。
| 1 2 3 4 5 6 7 8 9 10 11 12 | +------------+--------------+-----------+-------------+ | student_id | student_name | course_id | course_name | +------------+--------------+-----------+-------------+ |          3 | 宇藤         |        10 | 数学        | |          1 | 安藤         |        10 | 数学        | |          4 | 江藤         |        11 | 物理学      | |          3 | 宇藤         |        11 | 物理学      | |          1 | 安藤         |        11 | 物理学      | |          4 | 江藤         |        13 | 天文学      | |          3 | 宇藤         |        13 | 天文学      | +------------+--------------+-----------+-------------+ 7 rows in set (0.00 sec) | 
LEFT OUTER JOIN
LEFT OUTER JOINは、先に指定されたテーブル(左テーブル)の全レコードに対して、JOINで指定したレコードを対応させる。左テーブルに対応するレコードがないときはNULLになる。LEFT JOINと書いても同じ。
以下のクエリーは、studentsの全学生データに対してstudent_coursesの履修科目データを左結合させる。studentsには登録されているがstudent_coursesにない学生(学科を履修していない学生)についてはNULLになる。
| 1 2 3 4 5 6 7 | SELECT   st.id AS student_id,   st.name,   stcs.course_id FROM students AS st LEFT JOIN student_courses AS stcs   ON st.id = stcs.student_id; | 
実行結果は以下の通りで、学生IDの伊藤君はstudent_coursesテーブルに存在しないので、course_idがNULLになっている。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | +------------+--------+-----------+ | student_id | name   | course_id | +------------+--------+-----------+ |          1 | 安藤   |        11 | |          1 | 安藤   |        10 | |          2 | 伊藤   |      NULL | |          3 | 宇藤   |        13 | |          3 | 宇藤   |        11 | |          3 | 宇藤   |        10 | |          4 | 江藤   |        13 | |          4 | 江藤   |        11 | +------------+--------+-----------+ 8 rows in set (0.00 sec) | 
学科名も欲しい場合は、coursesテーブルを左結合させる。
| 1 2 3 4 5 6 7 8 9 10 | SELECT   st.id AS student_id,   st.name AS student_name,   cs.id AS course_id,   cs.name AS course_name FROM students AS st LEFT JOIN student_courses AS stcs   ON st.id = stcs.student_id LEFT JOIN courses AS cs   ON stcs.course_id = cs.id; | 
実行結果。学科を履修していない伊藤君のデータは、course_nameについてもNULLになる。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | +------------+--------------+-----------+-------------+ | student_id | student_name | course_id | course_name | +------------+--------------+-----------+-------------+ |          1 | 安藤         |        11 | 物理学      | |          1 | 安藤         |        10 | 数学        | |          2 | 伊藤         |      NULL | NULL        | |          3 | 宇藤         |        13 | 天文学      | |          3 | 宇藤         |        11 | 物理学      | |          3 | 宇藤         |        10 | 数学        | |          4 | 江藤         |        13 | 天文学      | |          4 | 江藤         |        11 | 物理学      | +------------+--------------+-----------+-------------+ 8 rows in set (0.00 sec) | 
RIGHT OUTER JOIN
RIGHT JOINは後から指定されたテーブルの全データに対して、先に指定されたテーブルを結合させる。先に指定されたテーブルに対応するレコードがない場合にはNULLになる。RIGHT JOINと書いても同じ。
以下は、student_coursesテーブルのデータにcoursesテーブルのデータを右結合させている。どの学生にも履修されていない学科がある場合はNULLになる。
| 1 2 3 4 5 6 7 | SELECT   stcs.student_id,   cs.id AS course_id,   cs.name AS course_name FROM student_courses AS stcs RIGHT JOIN courses as cs   ON stcs.course_id = cs.id; | 
実行結果。化学はどの学生にも履修されていないのでNULLになっている。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | +------------+-----------+-------------+ | student_id | course_id | course_name | +------------+-----------+-------------+ |          3 |        10 | 数学        | |          1 |        10 | 数学        | |          4 |        11 | 物理学      | |          3 |        11 | 物理学      | |          1 |        11 | 物理学      | |       NULL |        12 | 化学        | |          4 |        13 | 天文学      | |          3 |        13 | 天文学      | +------------+-----------+-------------+ 8 rows in set (0.00 sec) | 
3つ以上のテーブルでは、最も右側のテーブルをRIGHT JOINを連ねる。最後以外のJOINはRIGHTがなくても同じ結果になる。
| 1 2 3 4 5 6 7 8 9 10 | SELECT   st.id AS student_id,   st.name AS student_name,   cs.id AS course_id,   cs.name AS course_name FROM student_courses AS stcs RIGHT JOIN students AS st   ON stcs.student_id = st.id RIGHT JOIN courses as cs   ON stcs.course_id = cs.id; | 
実行結果。履修されていない化学の学生IDと学生名がNULLになっている。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | +------------+--------------+-----------+-------------+ | student_id | student_name | course_id | course_name | +------------+--------------+-----------+-------------+ |          3 | 宇藤         |        10 | 数学        | |          1 | 安藤         |        10 | 数学        | |          4 | 江藤         |        11 | 物理学      | |          3 | 宇藤         |        11 | 物理学      | |          1 | 安藤         |        11 | 物理学      | |       NULL | NULL         |        12 | 化学        | |          4 | 江藤         |        13 | 天文学      | |          3 | 宇藤         |        13 | 天文学      | +------------+--------------+-----------+-------------+ 8 rows in set (0.00 sec) | 
RIGHT JOINのテーブルを入れ替えることで、LEFT JOINで同じ結果を得られる。履修科目に関する上の例をLEFT JOINで書きなおすと以下の通り。
| 1 2 3 4 5 6 7 8 9 10 | SELECT   st.id AS student_id,   st.name AS student_name,   cs.id AS course_id,   cs.name AS course_name FROM courses AS cs LEFT JOIN student_courses AS stcs   ON stcs.course_id = cs.id LEFT JOIN students AS st   ON stcs.student_id = st.id; | 
実行結果は同じ。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | +------------+--------------+-----------+-------------+ | student_id | student_name | course_id | course_name | +------------+--------------+-----------+-------------+ |          3 | 宇藤         |        10 | 数学        | |          1 | 安藤         |        10 | 数学        | |          4 | 江藤         |        11 | 物理学      | |          3 | 宇藤         |        11 | 物理学      | |          1 | 安藤         |        11 | 物理学      | |       NULL | NULL         |        12 | 化学        | |          4 | 江藤         |        13 | 天文学      | |          3 | 宇藤         |        13 | 天文学      | +------------+--------------+-----------+-------------+ 8 rows in set (0.00 sec) | 
FULL OUTER JOIN
FULL OUTER JOINは指定されたテーブルの全データを含める。いずれかのデータが存在しない場合はNULLとなる。テーブルのデータ群の和集合に相当する。
MySQLにはFULL JOINが定義されていないので、同等の機能はUNIONで実現する。
- 2つのテーブルの場合にはLEFT JOINとRIGHT JOINの結果をUNION
- 結合テーブルがある場合には、それぞれのLEFT JOINの結果をUNION
- UNIONの際に、各- SELECTのカラムを同じにしておく
以下は、students、coursesに対するstudent_coursesのLEFT JOINの結果をUNIONで結合している。科目を履修していない学生は学科がNULLとなり、履修されていない科目が学生がNULLとなる。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | SELECT   st.id AS student_id,   st.name AS student_name,   cs.id AS course_id,   cs.name AS course_name FROM students AS st LEFT JOIN student_courses AS stcs   ON st.id = stcs.student_id LEFT JOIN courses AS cs   ON stcs.course_id = cs.id UNION SELECT   st.id AS student_id,   st.name AS student_name,   cs.id AS course_id,   cs.name AS course_name FROM courses AS cs LEFT JOIN student_courses AS stcs   ON stcs.course_id = cs.id LEFT JOIN students AS st   ON stcs.student_id = st.id; | 
実行結果。学科を履修していない伊藤君の学科欄はNULLになり、だれにも履修されていない化学は学生欄がNULLになっている。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | +------------+--------------+-----------+-------------+ | student_id | student_name | course_id | course_name | +------------+--------------+-----------+-------------+ |          1 | 安藤         |        11 | 物理学      | |          1 | 安藤         |        10 | 数学        | |          2 | 伊藤         |      NULL | NULL        | |          3 | 宇藤         |        13 | 天文学      | |          3 | 宇藤         |        11 | 物理学      | |          3 | 宇藤         |        10 | 数学        | |          4 | 江藤         |        13 | 天文学      | |          4 | 江藤         |        11 | 物理学      | |       NULL | NULL         |        12 | 化学        | +------------+--------------+-----------+-------------+ 9 rows in set (0.00 sec) | 
カラム名の指定によって結果が違う
LEFT OUTER JOINのところで、学生IDと学科IDをstudents.id、couses.idのようにそれぞれのテーブルから指定していた。
一方で、同じIDをstudent_courseのstudent_id、couse_idで指定することもできる。こちらで指定すれば、識別のためのエイリアスを定義しなくていいので便利そうだ。
| 1 2 3 4 5 6 7 8 9 10 | SELECT   stcs.student_id,   st.name AS student_name,   stcs.course_id,   cs.name AS course_name FROM courses AS cs LEFT JOIN student_courses AS stcs   ON stcs.course_id = cs.id LEFT JOIN students AS st   ON stcs.student_id = st.id; | 
しかしこれらを使うと、OUTER JOINの際に存在しないIDとして扱われてNULLになってしまう。
上のクエリーを実行した結果が以下で、化学を履修している学生がいないので、student_coursesに該当するデータがなく、student_idとcourse_idがNULLになっている。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | +------------+--------------+-----------+-------------+ | student_id | student_name | course_id | course_name | +------------+--------------+-----------+-------------+ |          3 | 宇藤         |        10 | 数学        | |          1 | 安藤         |        10 | 数学        | |          4 | 江藤         |        11 | 物理学      | |          3 | 宇藤         |        11 | 物理学      | |          1 | 安藤         |        11 | 物理学      | |       NULL | NULL         |      NULL | 化学        | |          4 | 江藤         |        13 | 天文学      | |          3 | 宇藤         |        13 | 天文学      | +------------+--------------+-----------+-------------+ 8 rows in set (0.00 sec) | 
これらを表示させたいときには、LEFT OUTER JOINの例のように、左結合される側(全データが使われる側)のテーブルでカラムを指定するとよい。